• Stars
    star
    1,446
  • Rank 32,535 (Top 0.7 %)
  • Language
    Haskell
  • License
    BSD 3-Clause "New...
  • Created almost 13 years ago
  • Updated over 5 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A GHC-based Haskell to JavaScript compiler

Haste

Build Status

A compiler to generate JavaScript code from Haskell.

It even has a website and a mailing list.

Features

  • 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 of Vagrant, 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

Installation

You have three options for getting Haste: installing from Hackage, from Github or from one of the pre-built binary 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 add path/to/haste-compiler/bin to your $PATH. The Debian package as well as the Windows installer and the optional install script included in the generic Linux package take care of this automatically.

Or, you can install the latest stable version from Hackage:

$ cabal install haste-compiler
$ haste-boot

Building from Github source is equally easy. After checking out the source, cd to the source tree and run:

$ cabal install
$ haste-boot --force --local

Alternatively, you may also build from Github source using Stack:

$ stack install
$ haste-boot --force --local

See doc/building.md for more information about build requirements and procedures for the various platforms.

If you are having problems with the haste-cabal installed by haste-boot, you can try building it from scratch and then passing the --no-haste-cabal flag to haste-boot:

$ git clone https://github.com/valderman/cabal.git
$ cd cabal && git checkout haste-cabal
$ cd Cabal && cabal install
$ cd ../cabal-install && cabal install

When 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 particular test by executing ./runtests.sh NameOfTest. The test suite uses the nodejs interpreter by default, but this may be modified by setting the JS environment variable as such: JS=other-js-interpreter ./runtests.sh. Other JavaScript interpreters may or may not work. runtests.sh isn’t downloaded when installing from 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, apply patches/closure-argument-removal.patch and build it as you normally would. This is not usually necessary however, as haste-boot fetches a pre-compiled Closure binary when run.

For more detailed build instructions, see doc/building.md.

Haste has been tested to work on Windows and OSX platforms, but is primarily developed on GNU/Linux. As such, running on a GNU/Linux platform will likely get you less bugs.

Usage

To compile your Haskell program to a JavaScript blob ready to be included in an HTML document or run using a command line interpreter:

$ hastec myprog.hs

This is equivalent to calling ghc --make myprog.hs; Main.main will be called as 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.hs

Haste also has its own set of command line arguments. Invoke it with --help to 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 might want to use the CPP extension for conditional compilation. Haste defines the preprocessor symbol __HASTE__ in all modules it compiles. This symbol may also be used to differentiate between Haste versions, since it is defined as an integer representation of the current Haste version. Its format is MAJOR*10 000 + MINOR*100 + MICRO. Version 1.2.3 would thus be represented as 10203, and 0.4.3 as 403.

Haste also comes with wrappers for cabal and ghc-pkg, named haste-cabal and haste-pkg respectively. You can use them to install packages just as you would with vanilla GHC and cabal:

$ haste-cabal install mtl

Finally, you can interact with JavaScript code using the Haste.Foreign module in the bundled haste-lib library. See doc/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 JS string manipulation, etc.

For more information on how Haste works, see the 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 for haste-lib, which resides in the libraries/haste-lib directory, and the small programs in the examples directory, to get started.

Interfacing with JavaScript

When writing programs you will probably want to use some native JavaScript in your program; bindings to native libraries, for instance. The preferred way of doing this is the Haste.Foreign module:

{-# LANGUAGE OverloadedStrings #-}
import Haste.Foreign

addTwo :: Int -> Int -> IO Int
addTwo = ffi "(function(x, y) {return x + y;})"

The ffi function is a little bit safer than the GHC FFI in that it enforces some 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 JavaScript code base, you can export selected functions from your Haste program and call them from JavaScript:

fun.hs:

{-# LANGUAGE OverloadedStrings #-}
import Haste.Foreign
import Haste.Prim (toJSStr)

fun :: Int -> String -> IO String
fun n s = return $ "The number is " ++ show n ++ " and the string is " ++ s

main = do
  export "fun" fun

legacy.js:

function mymain() {
  console.log(Haste.fun(42, "hello"));
}

...then compile with:

$ hastec '--start=$HASTE_MAIN(); mymain();' --with-js=legacy.js fun.hs

fun.hs will export the function fun when its main function is run. Our JavaScript obviously needs to run after that, so we create our "real" main function in legacy.js. Finally, we tell the compiler to start the program by first executing Haste's main function (the $HASTE_MAIN gets replaced by whatever name the compiler chooses for the Haste main) and then executing our own mymain.

The mechanics of Haste.Foreign are described in detail in this paper.

Effortless type-safe client-server communication

Using the framework from the Haste.App module hierarchy, you can easily write web applications that communicate with a server without having to write a single line of AJAX/WebSockets/whatever. Best of all: it's completely type safe.

In essence, you write your web application as a single program - no more forced separation of your client and server code. You then compile your program once using Haste and once using GHC, and the two compilers will magically generate client and server code respectively.

You will need to have the same libraries installed with both Haste and vanilla GHC (unless you use conditional compilation to get around this). haste-compiler comes bundled with all of haste-lib, so you only 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 binary generated by the native compilation pass only communicates with the client part using WebSockets and does not serve any files on its own.

Examples of Haste.App in action is available in examples/haste-app and examples/chatbox.

For more information about how exactly this works, see this paper.

Base library and documentation

You can build your own set of docs for haste-lib by running cabal haddock in the Haste base directory as with any other package.

Or you could just look at the online docs.

Libraries

Haste is able to use standard Haskell libraries. However, some primitive operations are still not implemented which means that any code making use of them will give you a compiler warning, then die at runtime with an angry error. Some libraries also depend on external C code - if you wish to use such a library, you will need to port the C bits to JavaScript yourself (perhaps using Emscripten) and link them into your program using --with-js.

Known issues

  • Not all GHC primops are implemented; if you encounter an unimplemented primop, please report it together with a small test case that demonstrates the 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 preserve Function.length. haste-boot bundles a compatibility patched version of Closure which does preserve this property. Invoking hastec with the --opt-minify option will use this patched version to minify the generated code with advanced optimizations.

More Repositories

1

selda

A type-safe, high-level SQL library for Haskell
Haskell
478
star
2

4koma

A TOML 1.0 parser library for Kotlin
Kotlin
73
star
3

konbini

Parser library for Kotlin
Kotlin
44
star
4

bt-reload-headphones

Workaround for wonky Sony (possibly other) BT headphones
Shell
28
star
5

lambdascript

Ugly prototype language for strongly typed, lazy, purely functional client side web scripting
Haskell
25
star
6

ghc-simple

Simplified interface to the GHC API
Haskell
24
star
7

shellmate

Write type-safe shell scripts in Haskell
Haskell
14
star
8

fursuit

FUnctional Reactivity with Signals Using a sIngle Thread of control
Haskell
11
star
9

ghc-sd

Build a GHC which produces shared libraries without runtime Haskell dependencies
Dockerfile
10
star
10

haste-app

Development version of Haste.App
Haskell
9
star
11

data-embed

Bundle data files inside executables, for easy access and single file distribution.
Haskell
8
star
12

squeekboard-sway

Sway-friendly mod of the original Squeekboard keyboard
Rust
7
star
13

haste-deck

Create presentation slides and simple web pages using an intuitive DSL
Haskell
7
star
14

zalgo

A somewhat flexible Zalgo̐ te̳͜x̥̖̉̓͞t̍̌̔ ̀̃t̴̢̞̜͓̝r̶̬̆̂̒͟á̧̡͎͔̯̰̕n̹̾̓ͬͦ̍͘ṡ̢͓͉ͮ͆l̠̖̹̗̳̖̽̌ͤ͞a͚̭͙̹̲ͭͩt͈͐o̢̭͇͍̟͐ͬ̾ͪ͜r͇.̸̅ͭ̐̀̊ͨ͛
Haskell
7
star
15

ctagsymbols

CTags workspace symbol provider extension for Visual Studio Code
JavaScript
6
star
16

haste-standalone

Create zero configuration standalone Haste.App web apps
Haskell
6
star
17

aoc21

Advent of Code 2021 in Haskell
Haskell
6
star
18

wanchan

NyaaTorrents watcher, scraper, explorer and downloader - now with a fancy web interface
Haskell
6
star
19

dpress

Generating random sequences using n-grams in Haskell
Haskell
4
star
20

threefish

Haskell implementation of the Threefish block cipher and the Skein hash function built on it.
Haskell
4
star
21

ask

User input convenience functions for console programs
Haskell
4
star
22

mcctl

Robust and simple Minecraft daemon manager
Haskell
3
star
23

threefish.js

Javascript implementation of the Threefish block cipher and Skein hash function
3
star
24

advent-2018

Haskell solutions to Advent of Code 2018
Haskell
3
star
25

haskell-mpv

Thread-safe Haskell wrapper around libmpv
Haskell
3
star
26

domplate

Haskell
2
star
27

picube

Haste powered info screens, photo frames, etc.
Haskell
2
star
28

mat

What's for lunch today around Grönsakstorget, Gothenburg?
Python
2
star
29

thpp

Template Haskell as a preprocessor
Haskell
2
star
30

pix

Haskell
2
star
31

rfinder

Ugly hack for locating resource clusters in Minecraft maps.
Haskell
2
star
32

tini

Tiny INI file and generic configuration library
Haskell
2
star
33

lambnyaa

Haskell
1
star
34

ffi-paper

TeX
1
star
35

erlbot

IRC bot written in Erlang
Erlang
1
star
36

himitsu

Haskell
1
star
37

typhpist

A bunch of classes to allow for type safe generation of valid XHTML documents with PHP.
PHP
1
star
38

datastrukt-travelgui

Haskell
1
star
39

kagamin

Haskell
1
star
40

aplite-benchmarks

Benchmarks comparing Aplite with non-Aplite Haskell and hand-rolled JavaScript
Haskell
1
star
41

ccwf

Chalmers Course Website Framework
Haskell
1
star
42

phdtools

Timekeeping tool for multiple projects
Haskell
1
star
43

servermanager

Haskell
1
star
44

grape

Generic Reification of ADTs and Patterns in EDSLs
Haskell
1
star
45

twofish

A pure-haskell implementation of the Twofish symmetric block encryption cipher
Haskell
1
star
46

hangouts-logbaker

Working with Hangouts logs from Google Takeaway in Haskell and SQLite
Haskell
1
star