- Notifications
You must be signed in to change notification settings - Fork107
A GHC-based Haskell to JavaScript compiler
License
valderman/haste-compiler
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
A compiler to generate JavaScript code from Haskell.
It even has awebsite and amailing list.
- Seamless, type-safe single program framework for client-server communication
- Support for modern web technologies such as WebSockets, WebStorage and Canvas
- Simple JavaScript interoperability
- Generates small, fast programs
- Supports all GHC extensions except Template Haskell
- Uses standard Haskell libraries
- Cabal integration
- Simple, one-step build; no need for error prone Rube Goldberg machines ofVagrant, VirtualBox, GHC sources and other black magic
- Concurrency and MVars with Haste.Concurrent
- Unboxed arrays, ByteArrays, StableNames and other low level features
- Low-level DOM base library
- Easy integration with Google's Closure compiler
- Works on Windows, GNU/Linux and Mac OS X
You have three options for getting Haste: installing from Hackage, fromGithub or from one of the pre-builtbinary packages.In the first two cases, you need to add add Cabal's bin directory, usually~/.cabal/bin, to your$PATH if you haven't already done so.When installing from the Mac, portable Windows or generic Linux package,you may want to addpath/to/haste-compiler/bin to your$PATH.The Debian package as well as the Windows installer and the optionalinstall script included in the generic Linux packagetake care of this automatically.
Or, you can install the latest stable version from Hackage:
$ cabal install haste-compiler$ haste-bootBuilding from Github source is equally easy. After checking out the source,cd to the source tree and run:
$ cabal install$ haste-boot --force --localAlternatively, you may also build from Github source using Stack:
$ stack install$ haste-boot --force --localSeedoc/building.md for more information about build requirements andprocedures for the various platforms.
If you are having problems with thehaste-cabal installed byhaste-boot,you can try building it from scratch and then passing the--no-haste-cabalflag tohaste-boot:
$ git clone https://github.com/valderman/cabal.git$ cd cabal && git checkout haste-cabal$ cd Cabal && cabal install$ cd ../cabal-install && cabal installWhen installing Haste from GitHub, you should probably run the test suite first,to verify that everything is working. To do that, execute./runtests.sh in the Haste root directory. You may also run only a particulartest by executing./runtests.sh NameOfTest. The test suite uses thenodejsinterpreter by default, but this may be modified by setting theJS environmentvariable as such:JS=other-js-interpreter ./runtests.sh. Other JavaScriptinterpreters may or may not work.runtests.sh isn’t downloaded when installingfrom Hackage. You would have to download it from GitHub.
To build the patched Closure compiler used when compiling using--opt-minify,get the Closure source, applypatches/closure-argument-removal.patch andbuild it as you normally would. This is not usually necessary however,ashaste-boot fetches a pre-compiled Closure binary when run.
For more detailed build instructions, seedoc/building.md.
Haste has been tested to work on Windows and OSX platforms, but is primarilydeveloped on GNU/Linux. As such, running on a GNU/Linux platform will likelyget you less bugs.
To compile your Haskell program to a JavaScript blob ready to be included in anHTML document or run using a command line interpreter:
$ hastec myprog.hsThis is equivalent to calling ghc --make myprog.hs; Main.main will be calledas soon as the JS blob has finished loading.
You can pass the same flags to hastec as you'd normally pass to GHC:
$ hastec -O2 -fglasgow-exts myprog.hsHaste also has its own set of command line arguments. Invoke it with--helpto read more about them. In particular--opt-all,--opt-minify,--start and--with-js should be fairly interesting.
If you want your package to compile with both Haste and, say, GHC, you mightwant to use the CPP extension for conditional compilation. Haste defines thepreprocessor symbol__HASTE__ in all modules it compiles. This symbol mayalso be used to differentiate between Haste versions, since it is definedas an integer representation of the current Haste version. Its format isMAJOR*10 000 + MINOR*100 + MICRO. Version 1.2.3 would thus be represented as10203, and 0.4.3 as 403.
Haste also comes with wrappers for cabal and ghc-pkg, named haste-cabal andhaste-pkg respectively. You can use them to install packages just as you wouldwith vanilla GHC and cabal:
$ haste-cabal install mtlFinally, you can interact with JavaScript code using theHaste.Foreignmodule in the bundledhaste-lib library.Seedoc/js-externals.txt for more information about that.This library also contains all sorts of functionality for DOM manipulation,event handling, preemptive multitasking, canvas graphics, native JSstring manipulation, etc.
For more information on how Haste works, seethe Haste Report,though beware that parts of Haste may have changed quite a bit.
You should also have a look at the documentation and/or source code forhaste-lib, which resides in thelibraries/haste-lib directory, and thesmall programs in theexamples directory, to get started.
When writing programs you will probably want to use some native JavaScriptin your program; bindings to native libraries, for instance.The preferred way of doing this is theHaste.Foreign module:
{-# LANGUAGE OverloadedStrings #-}import Haste.ForeignaddTwo :: Int -> Int -> IO IntaddTwo = ffi "(function(x, y) {return x + y;})"Theffi function is a little bit safer than the GHC FFI in that it enforcessome type invariants on values returned from JS, and is more convenient.Performance-wise, it is roughly as fast as the GHC FFI except for complex types(lists, records, etc.) where it is an order of magnitude faster.
If you do not feel comfortable throwing out your entire legacy JavaScriptcode base, you can export selected functions from your Haste program and callthem from #"auto">fun.hs:
{-# LANGUAGE OverloadedStrings #-}import Haste.Foreignimport Haste.Prim (toJSStr)fun :: Int -> String -> IO Stringfun n s = return $ "The number is " ++ show n ++ " and the string is " ++ smain = do export "fun" funlegacy.js:
function mymain() { console.log(Haste.fun(42, "hello"));}...then compile with:
$ hastec '--start=$HASTE_MAIN(); mymain();' --with-js=legacy.js fun.hsfun.hs will export the functionfun when itsmain function is run.Our JavaScript obviously needs to run after that, so we create our "real" mainfunction inlegacy.js. Finally, we tell the compiler to start the program byfirst executing Haste'smain function (the$HASTE_MAIN gets replaced bywhatever name the compiler chooses for the Hastemain) and then executingour ownmymain.
The mechanics ofHaste.Foreign are described in detail in thispaper.
Using the framework from theHaste.App module hierarchy, you can easily writeweb applications that communicate with a server without having to write asingle line of AJAX/WebSockets/whatever. Best of all: it's completely typesafe.
In essence, you write your web application as a single program - no more forcedseparation of your client and server code. You then compile your program onceusing Haste and once using GHC, and the two compilers will magically generateclient and server code respectively.
You will need to have the same libraries installed with both Haste and vanillaGHC (unless you use conditional compilation to get around this).haste-compiler comes bundled with all ofhaste-lib, so youonly need to concern yourself with this if you're using third party libraries.You will also need a web server, to serve your HTML and JS files; the binarygenerated by the native compilation pass only communicates with the client partusing WebSockets and does not serve any files on its own.
Examples of Haste.App in action is available inexamples/haste-app andexamples/chatbox.
For more information about how exactly this works, see thispaper.
You can build your own set of docs for haste-lib by runningcabal haddock in the Haste base directory as with any other package.
Or you could just look atthe online docs.
Haste is able to use standard Haskell libraries. However, some primitiveoperations are still not implemented which means that any code making useof them will give you a compiler warning, then die at runtime with an angryerror. Some libraries also depend on external C code - if you wish to use sucha library, you will need to port the C bits to JavaScript yourself (perhapsusing Emscripten) and link them into your program using--with-js.
Not all GHC primops are implemented; if you encounter an unimplementedprimop, please report it together with a small test case that demonstratesthe problem.
Template Haskell is still broken.
Generated code is not compatible with the vanilla Closure compiler's
ADVANCED_OPTIMIZATIONS, as it is not guaranteed to preserveFunction.length.haste-bootbundles a compatibility patched version of Closure which doespreserve this property. Invokinghastecwith the--opt-minifyoptionwill use this patched version to minify the generated code with advancedoptimizations.
About
A GHC-based Haskell to JavaScript compiler
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.