Functional Reactive Web Interfaces with GHCJS and sodium

Note

Some of the information here is outdated. Follow the installation instructions in the README. Using a virtual machine is no longer recommended and the ghcjs-build repository is no longer maintained.

Updated examples can be found in the ghcjs-examples repository, or click the source link. The safety specifications in the JavaScript foreign function interface have been changed slightly, see GHCJS.Foreign for more information. In particular, you need "interruptible" instead of "safe" for asynchronous imports.

Introduction

Since the last post we have made a number of changes to GHCJS. Dan Frumin, who is using GHCJS for his Google Summer of Code project, has contributed an improved build script. Hamish Mackenzie has ported an initial version of ghcjs-dom to our new code generator. Ghcjs-dom contains generated bindings for the DOM API that allow you to write applications that run in the browser with GHCJS, but also as native code, with a webkit frame.

I have added travis support to the repository, so our test suite will be run for every commit and pull request to the GHCJS and shims repositories. I have also updated the prebuilt vagrant virtual machine image to incorporate the latest bugfixes and updates to ByteArray# and pointers.

This time we are going to be looking at functional reactive programming for the web. Since GHCJS has a full-featured Haskell runtime, with support for threading, async exceptions and STM, any existing FRP library should work. We will be using sodium for the examples. If you have trouble getting your favourite FRP library to work with GHCJS, you can contact us on IRC (#ghcjs on freenode), the mailing list, or file a bug report.

Quick start

Since GHCJS depends on GHC HEAD and Cabal, with a few patches that have not yet been merged, the easiest way to get started is with a vagrant virtual machine:

$ git clone https://github.com/ghcjs/ghcjs-build.git
$ cd ghcjs-build
$ git checkout prebuilt
$ vagrant up

Log into the virtual machine with:

$ vagrant ssh

You can find the examples in /home/vagrant/ghcjs-examples/weblog. To view the result in the browser, start the preinstalled warp web server on the virtual machine with

$ vagrant ssh -c warp

and go to http://localhost:3030/ghcjs-examples/weblog/ (Warp listens on port 3000, Vagrant is configured to forward port 3030 of the host machine to that).

For more information and other installation options, see the GHCJS introduction post on this weblog.

Events and behaviours

Functional reactive programming is based on two composable abstractions: behaviours (time-varying values) and events (happening at discrete points in time). Sodium is a simple push-based library that implements these abstractions: Everything is driven by something pushing a new value to a behaviour or firing a new event.

Note that sodium depends on weak references to clean up unused events. If you want to customize GHCJS’ memory management, do not disable the heap scanner completely if you often create new behaviours and events.

Let’s get started with a simple example. First we create a button that fires an event every time it’s clicked. We count the number of events using sodium’s built-in count behaviour. Finally, we listen to the values in this behaviour and update the text in counterDiv after a change:

-- run code: http://hdiff.luite.com/ghcjs/examples/counter/
-- full source: https://github.com/ghcjs/ghcjs-examples/blob/master/weblog/counter/counter.hs
{-# LANGUAGE OverloadedStrings #-}

module Main where

import           Control.Monad
import           Control.Monad.IO.Class
import           Data.Default
import           Data.Text (Text)
import qualified Data.Text as T

import           JavaScript.JQuery hiding (Event)

import           FRP.Sodium

main :: IO ()
main = do
  body <- select "body"
  buttonEvent <- reactiveButton "Click Me!" body
  counterDiv <- select "<div />"
  appendJQuery counterDiv body
  sync $ do
    counter <- count buttonEvent
    listen (values counter) (\n -> void $
            setText (T.pack . show $ n) counterDiv)
  return ()

reactiveButton :: Text -> JQuery -> IO (Event ())
reactiveButton label parent = do
  (evt, a) <- sync newEvent
  button <- select "<button />"
  setText label button
  appendJQuery button parent
  let handler _ = sync (a ())
  on handler "click" def button
  return evt

Since we use ghcjs-jquery to add the user interface elements, we need to load the jQuery library in our HTML file, also we need some CSS for the examples:

<!DOCTYPE html>
<html>
  <head>
    <script language="javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
    <script language="javascript" src="lib.js"></script>
    <script language="javascript" src="rts.js"></script>
    <script language="javascript" src="lib1.js"></script>
    <script language="javascript" src="out.js"></script>
    <style type="text/css"> html, body { width: 100%; height: 100%; margin: 0; padding: 0; }</style>
  </head>
  <body>
  </body>
  <script language="javascript">

h$main(h$mainZCMainzimain);

  </script>
</html>

We will use the same HTML throughout this weblog post.

Button clicks are a typical Event, since they happen at discrete points in time, but many user interface elements have values that change over time. These are better modeled with a Behaviour. The next example uses text input fields and a select menu as reactive elements:

-- run code: http://hdiff.luite.com/ghcjs/examples/calculator/
-- full source: https://github.com/ghcjs/ghcjs-examples/blob/master/weblog/calculator/calculator.hs
-- begin collapse
{-# LANGUAGE OverloadedStrings, ScopedTypeVariables      #-}

module Main where

import           Control.Applicative
import           Control.Monad
import           Data.Default
import           Data.Text (Text)
import qualified Data.Text as T
import           Text.Read

import           JavaScript.JQuery

import           FRP.Sodium
-- end collapse

main :: IO ()
main = do
  body <-       select "body"
  [op1, op2] <- replicateM 2 $
     fmap (fmap (readMaybe . T.unpack)) (reactiveTextInput "0" body)
  let items = [ ("add"     , arithBehaviour op1 op2 (+))
              , ("multiply", arithBehaviour op1 op2 (*))
              ]
  sel <- reactiveSelect items body
  output <- select "<div />"
  appendJQuery output body
  sync $ do
    result <- switch sel
    listen (values result) $ \v -> void $
      setText (maybe "invalid input" (T.pack.show) v) output
  return ()

arithBehaviour :: Behaviour (Maybe Integer)
               -> Behaviour (Maybe Integer)
               -> (Integer -> Integer -> Integer)
               -> Behaviour (Maybe Integer)
arithBehaviour op1 op2 f = liftA2 f <$> op1 <*> op2

reactiveTextInput :: Text -> JQuery -> IO (Behaviour Text)
reactiveTextInput value parent = do
-- begin collapse
  (b, a) <- sync (newBehaviour value)
  input <- select "<input type='text' />"
  setVal value input
  appendJQuery input parent
  let handler _ = sync . a =<< getVal input
  on handler "keyup change" def input
  return b
-- end collapse

reactiveSelect :: [(Text,a)] -> JQuery -> IO (Behaviour a)
reactiveSelect items parent = do
-- begin collapse
  (b, a) <- sync (newBehaviour . snd . head $ items)
  sel <- select "<select />"
  forM_ (zip [(0::Int)..] items) $ \(n,(name,_)) -> do
    opt <- select "<option />"
    setAttr "value" (T.pack . show $ n) opt
    when (n == 0) $ void (setAttr "selected" "true" opt)
    setText name opt
    appendJQuery opt sel
  appendJQuery sel parent
  let handler _ = sync . a =<< snd.(items !!).read.T.unpack <$> getVal sel
  on handler "change" def sel
  return b
-- end collapse

The text input field is of type Behaviour Text, it has a time-dependent text value, which gets updated by handling the keyup and change JavaScript events on the HTML input element with jQuery.

The select menu is polymorphic: Every menu item has a label an a value of type a. The values can themselves be Behaviours: In the example, every value is a Behaviour (Maybe Integer). We use sodium’s switch function to create a new Behaviour that dynamically switches between multiplying and adding the numbers.

Beside sodium’s built-in primitives, the most important way to work with Behaviours is their Applicative instance. We use this in the example to combine the values of the two operands into a new Behaviour (Actually we use Applicative twice! One more time to lift the operator from Integer -> Integer -> Integer to Maybe Integer -> Maybe Integer -> Maybe Integer).

Handling mouse input

Not only form elements can be a behaviour. In the next example, we have the current mouse pointer position as a Behaviour (Double, Double), indicating the distance in pixels from the top left corner of the document.

Open the example and move your mouse pointer over the page. The changes of the mouse Behaviour automatically trigger updates of the position of the objects. Again we use the Applicative instance for Behaviour to combine two inputs: The time (derived from the mouse position) and the position of the parent object.

-- run code: http://hdiff.luite.com/ghcjs/examples/mouse/
-- full source: https://github.com/ghcjs/ghcjs-examples/blob/master/weblog/mouse/mouse.hs
-- begin collapse
{-# LANGUAGE CPP, JavaScriptFFI, ForeignFunctionInterface,
             EmptyDataDecls, OverloadedStrings,
             ScopedTypeVariables
  #-}
module Main where

import           Control.Applicative
import           Data.Default
import           Data.Text (Text)
import qualified Data.Text as T

import           GHCJS.Types
import           GHCJS.Foreign
import           GHCJS.Marshal
import           JavaScript.JQuery

import           FRP.Sodium

#ifdef __GHCJS__
-- create an element in the SVG namespace
foreign import javascript unsafe "document.createElementNS('http://www.w3.org/2000/svg',$1)"
   createSvg :: JSString -> IO Element
foreign import javascript unsafe "document.getElementsByTagName($1)"
   getElementsByTagName :: JSString -> IO (JSArray a)
foreign import javascript unsafe "$3.setAttribute($1,$2)"
   setAttribute :: JSString -> JSRef a -> JSRef b -> IO ()
foreign import javascript unsafe "$2.appendChild($1)"
   appendChild :: Element -> Element -> IO ()
#else
createSvg = undefined
appendChild = undefined
getElementsByTagName = undefined
setAttribute = undefined
#endif

setAttribute' :: ToJSRef a => JSString -> a -> JSRef b -> IO ()
setAttribute' a v o = toJSRef v >>= \v' -> setAttribute a v' o
-- end collapse

main = do
  body <- indexArray 0 =<< getElementsByTagName "body"
  svg <- createSvg "svg"
  appendChild svg body
  setAttribute' "width" (400::Int) svg >> setAttribute' "height" (400::Int) svg
  t <- fmap ((*5) . fst) <$> mousePosition body
  let sun   = pure (200, 200)
      earth = object (1/365) 150 sun   t
      moon  = object (1/30)  25  earth t
  drawObject svg "yellow" 20 sun
  drawObject svg "blue"   8  earth
  drawObject svg "grey"   3  moon

object :: Double
       -> Double
       -> Behaviour (Double, Double)
       -> Behaviour Double
       -> (Behaviour (Double, Double))
object speed r center time =
   (,) <$> liftA2 xpos center time <*> liftA2 ypos center time
     where
       xpos (x,_) t = x + r * cos (speed * t)
       ypos (_,y) t = y + r * sin (speed * t)

drawObject :: Element -> Text -> Double -> Behaviour (Double, Double) -> IO ()
drawObject parent color r x = do
  putStrLn (T.unpack color)
  circle <- createSvg "circle"
  let p .= v = setAttribute' p v circle
  "fill" .= color >> "r" .= r
  appendChild circle parent
  sync $ listen (values x) $
    \(x,y) -> "cx" .= x >> "cy" .= y
  return ()

mousePosition :: Element -> IO (Behaviour (Double, Double))
mousePosition elem = do
  (b, push) <- sync $ newBehaviour (0,0)
  let handler ev = do
        x <- pageX ev
        y <- pageY ev
        sync $ push (x,y)
  on handler "mousemove" def =<< selectElement elem
  return b

Timers and animation

So far, all events we have seen were caused directly by user input from the keyboard or mouse. In the next example we will see an external (timer) event source and behaviours with an internal state to do a simple (mostly incorrect) physics simulation of balls being attracted to your mouse pointer.

If you compile the example yourself, you need to have ball.png in your executable directory, in addition to the index.html listed above.

Main creates 10 balls, displayed as absolutely positioned image elements. After that, it enters a main loop, which repeatedly fires a stepper event that contains the time elapsed since the last event. The event is combined with the current mouse position and browser window size, using the snapshotWith primitive, which samples the current value of a behaviour at the time an event fires.

After each stepper update, the loop calls threadDelay 1, which lets the Haskell scheduler yield briefly (since we don’t have any other runnable Haskell threads), to let the browser redraw the window and process new mouse events.

The balls themselves use sodium’s collectE primitive to listen for timestep events, updating the postion and velocity of the ball’s internal state by doing a simple numerical integration step. Externally, only the position is visible.

The number of steps per second depends on the browser and the machine it runs on, therefore the update function uses the time value in the event, the number of milliseconds since the last event, to determine the step size, making the acceleration and velocity of the balls mostly independent of the machine and browser (faster updates, and thus smaller steps, still result in a slightly more accurate simulation).

-- run code: http://hdiff.luite.com/ghcjs/examples/balls1/
-- full source: https://github.com/ghcjs/ghcjs-examples/blob/master/weblog/balls1/balls1.hs
-- begin collapse
{-# LANGUAGE CPP, OverloadedStrings, TypeFamilies, JavaScriptFFI #-}

module Main where

import           Control.Applicative
import           Control.Concurrent
import           Control.Monad
import           Data.Default
import           Data.VectorSpace
import           System.Random

import           FRP.Sodium

import           JavaScript.JQuery hiding (Event)
import           GHCJS.Types
import           GHCJS.Foreign

#ifdef __GHCJS__
foreign import javascript unsafe "Date.now()"
  now :: IO Double
foreign import javascript unsafe "$3.css($1,$2+'px')"
  setCssPx :: JSString -> Double -> JQuery -> IO ()
#else
now            = return 0
setCssPx _ _ _ = undefined
#endif

data R2 = R2 { _x :: Double, _y :: Double }
  deriving (Show, Eq, Ord)

instance AdditiveGroup R2 where
  zeroV = R2 0 0
  R2 x1 y1 ^+^ R2 x2 y2 = R2 (x1+x2) (y1+y2)
  negateV (R2 x y) = R2 (negate x) (negate y)

instance VectorSpace R2 where
  type Scalar R2 = Double
  s *^ (R2 x y) = R2 (s*x) (s*y)

instance InnerSpace R2 where
  (R2 x1 y1) <.> (R2 x2 y2) = (x1*x2)+(y1*y2)
-- end collapse

main :: IO ()
main = do
  body <- select "body"
  bodySize <- size body
  mouse <- mousePosition body
  startSize <- sync (sample bodySize)
  (stepper, pushStepper) <- sync newEvent
  let stepper' = snapshotWith (,) stepper ((,) <$> mouse <*> bodySize)
  replicateM_ 10 (startPos bodySize >>= \start -> ball body start stepper')
  let step t0 = do
        t1 <- now
        sync (pushStepper $ t1-t0)
        threadDelay 1
        step t1
  step =<< now

startPos :: Behaviour R2 -> IO R2
startPos size = do
  R2 mx my <- sync (sample size)
  R2 <$> randomRIO (0,mx) <*> randomRIO (0,my)

ball :: JQuery
     -> R2
     -> Event (Double, (R2, R2))
     -> IO (Behaviour R2)
ball parent startPos step = do
  b <- select "<img src='ball.png' width='25' height='25' />"
  setCss "position" "absolute" b
  appendJQuery b parent
  let updCss prop f x = void (setCssPx prop (f x) b)
  pos <- sync (hold startPos =<< collectE upd initial step)
  sync (listen (values pos) $ \x -> updCss "left" _x x >> updCss "top" _y x)
  return pos
    where
      initial = (startPos, R2 0 0)
      upd (dt,(m,s)) (x,v) =
        let r          = m ^-^ x
            a          = (5 * recip (300 + magnitudeSq r)) *^ normalized r
            t@(x', v') = clamp s 25 (x ^+^ (dt *^ v)) ((0.9995 ** dt) *^ (v ^+^ (dt *^ a)))
        in  (x',t)

clamp :: R2 -> Double -> R2 -> R2 -> (R2, R2)
clamp size objSize x v = (R2 xx xy, R2 vx vy)
  where
    (xx, vx) = clamp' _x
    (xy, vy) = clamp' _y
    clamp' f
      | x' < 0    = (-x', abs v')
      | x' > m    = (2 * m - x', negate (abs v'))
      | otherwise = (x', v')
      where
        x' = f x
        v' = f v
        m  = f size - objSize

-- size of the element, in pixels
size :: JQuery -> IO (Behaviour R2)
size elem = do
-- begin collapse
  (b, push) <- sync . newBehaviour =<< dims
  let handler _ = sync . push =<< dims
  on handler "resize" def elem
  return b
    where
      dims = R2 <$> getWidth elem
                <*> getHeight elem
-- end collapse

-- the mouse position, in pixels from the top-left corner
mousePosition :: JQuery -> IO (Behaviour R2)
mousePosition elem = do
-- begin collapse
  (b, push) <- sync $ newBehaviour (R2 0 0)
  let handler ev = do
        x <- pageX ev
        y <- pageY ev
        sync $ push (R2 x y)
  on handler "mousemove" def elem
  return b
-- end collapse

Note that we use some foreign imports, getting the current time as a Double, and updating the CSS position of an element through jQuery. In both cases, we could have used existing functions like Data.Time.Clock.getCurrentTime and JavaScript.JQuery.setCss with the Show instance for Double to get the same result.

These functions are both supported but go through a lot of code: getCurrentTime uses emulation for the POSIX gettimeofday call, instance Show Double decodes the floating point to a significand and exponent, using Integer under the hood.

Since we run this from the animation loop, this affects the performance of our program. Fortunately, importing the lighter weight JavaScript alternatives can be done in just a few lines of code.

Smoother animation with requestAnimationFrame

The above example uses a loop in Haskell to trigger each animation step, calling threadDelay every iteration. While this works, it does not always result in a smooth animation: The updates are not synchronized with browser redraws, and the GHCJS scheduler uses JavaScript’s setTimeout function to reschedule itself, which can be a bit unpredictable in the time it takes for this.

Modern browsers support a better alternative: The window.requestAnimationFrame method (unfortunately the name is not standardized across browsers, so we have to test for a few different names) lets the browser run a JavaScript function just before the window is repainted. We can use this function to call back into Haskell and let sodium run one animation step.

GHCJS has two different ways to let JavaScript call back into Haskell code. Asynchronous callbacks (run directly with h$run or create from Haskell with GHCJS.Foreign.asyncCallback) start a regular Haskell thread in the background. The callback itself returns immediately.

For the animation here, we don’t want an asynchronous callback: The function used with requestAnimationFrame should perform an animation step immediately, updating all objects before returning. The other option, a synchronous callback, does exactly that. Synchronous code is more limited than asynchronous code: The callback will return immediately when the Haskell code tries to do an operation that would block (for example taking an empty MVar, or doing an asynchronous blocking FFI operation).

In the example below, it is possible that the thread blocks when trying run sync, since sodium uses an MVar lock internally. We can choose what happens when a synchronous thread blocks: Either the thread is aborted immediately, or it continues running asynchronously. Here we choose to abort the thread: The animation frame is simply dropped when something is holding the FRP lock.

-- run code: http://hdiff.luite.com/ghcjs/examples/balls2/
-- full source: https://github.com/ghcjs/ghcjs-examples/blob/master/weblog/balls2/balls2.hs
-- begin collapse
{-# LANGUAGE CPP, OverloadedStrings, TypeFamilies, JavaScriptFFI #-}

module Main where

import           Control.Applicative
import           Control.Monad
import           Data.Default
import           Data.IORef
import           Data.VectorSpace
import           System.Random

import           FRP.Sodium

import           JavaScript.JQuery hiding (Event)
import           GHCJS.Types
import           GHCJS.Foreign

#ifdef __GHCJS__
foreign import javascript unsafe "Date.now()" now :: IO Double
foreign import javascript unsafe "$3.css($1,$2+'px')"
  setCssPx :: JSString -> Double -> JQuery -> IO ()
-- end collapse
foreign import javascript unsafe
  "var req = window.requestAnimationFrame ||\
             window.mozRequestAnimationFrame ||\
             window.webkitRequestAnimationFrame ||\
             window.msRequestAnimationFrame;\
   var f = function() { $1(); req(f); };\
   req(f);" -- fixstr "
  animate :: JSFun (IO ()) -> IO ()
-- begin collapse
#else
now            = return 0
setCssPx _ _ _ = undefined
animate _      = undefined
#endif

data R2 = R2 { _x :: Double, _y :: Double }
  deriving (Show, Eq, Ord)

instance AdditiveGroup R2 where
  zeroV = R2 0 0
  R2 x1 y1 ^+^ R2 x2 y2 = R2 (x1+x2) (y1+y2)
  negateV (R2 x y) = R2 (negate x) (negate y)

instance VectorSpace R2 where
  type Scalar R2 = Double
  s *^ (R2 x y) = R2 (s*x) (s*y)

instance InnerSpace R2 where
  (R2 x1 y1) <.> (R2 x2 y2) = (x1*x2)+(y1*y2)
-- end collapse

main :: IO ()
main = do
  body <- select "body"
  bodySize <- size body
  mouse <- mousePosition body
  startSize <- sync (sample bodySize)
  (stepper, pushStepper) <- sync newEvent
  let stepper' = snapshotWith (,) stepper ((,) <$> mouse <*> bodySize)
  replicateM_ 10 (startPos bodySize >>= \start -> ball body start stepper')
  t <- newIORef =<< now
  let step = do
        t0 <- readIORef t
        t1 <- now
        sync (pushStepper $ t1-t0)
        writeIORef t t1
  animate =<< syncCallback False step

-- begin collapse
startPos :: Behaviour R2 -> IO R2
startPos size = do
  R2 mx my <- sync (sample size)
  R2 <$> randomRIO (0,mx) <*> randomRIO (0,my)

ball :: JQuery
     -> R2
     -> Event (Double, (R2, R2))
     -> IO (Behaviour R2)
ball parent startPos step = do
  b <- select "<img src='ball.png' width='25' height='25' />"
  setCss "position" "absolute" b
  appendJQuery b parent
  let updCss prop f x = void (setCssPx prop (f x) b)
  pos <- sync (hold startPos =<< collectE upd initial step)
  sync (listen (values pos) $ \x -> updCss "left" _x x >> updCss "top" _y x)
  return pos
    where
      initial = (startPos, R2 0 0)
      upd (dt,(m,s)) (x,v) =
        let r          = m ^-^ x
            a          = (5 * recip (300 + magnitudeSq r)) *^ normalized r
            t@(x', v') = clamp s 25 (x ^+^ (dt *^ v)) ((0.9995 ** dt) *^ (v ^+^ (dt *^ a)))
        in  (x',t)

clamp :: R2 -> Double -> R2 -> R2 -> (R2, R2)
clamp size objSize x v = (R2 xx xy, R2 vx vy)
  where
    (xx, vx) = clamp' _x
    (xy, vy) = clamp' _y
    clamp' f
      | x' < 0    = (-x', abs v')
      | x' > m    = (2 * m - x', negate (abs v'))
      | otherwise = (x', v')
      where
        x' = f x
        v' = f v
        m  = f size - objSize

-- size of the element, in pixels
size :: JQuery -> IO (Behaviour R2)
size elem = do
  (b, push) <- sync . newBehaviour =<< dims
  let handler _ = sync . push =<< dims
  on handler "resize" def elem
  return b
    where
      dims = R2 <$> getWidth elem
                <*> getHeight elem

-- the mouse position, in pixels from the top-left corner
mousePosition :: JQuery -> IO (Behaviour R2)
mousePosition elem = do
  (b, push) <- sync $ newBehaviour (R2 0 0)
  let handler ev = do
        x <- pageX ev
        y <- pageY ev
        sync $ push (R2 x y)
  on handler "mousemove" def elem
  return b
-- end collapse

Conclusion

We have seen several examples of functional reactive programming with GHCJS, handling user input and doing animations. Unfortunately for all of the examples we had to do some low-level work ourselves: Setting up mouse event handlers, adding HTML elements to the document. Even though Haskell and GHCJS make these steps relatively easy, we would really like to build a functional reactive user interface library that does this for us, with a collection of ready-made reactive widgets and a declarative way to set up the user interface.

If you have ideas on how to structure such a library, or are interested in helping, please comment, post to the mailing list, or join us on IRC in #ghcjs on freenode.

GHCJS introduction – Concurrent Haskell in the browser

Note

Some of the information here is outdated. Follow the installation instructions in the README. Using a virtual machine is no longer recommended and the ghcjs-build repository is no longer maintained.

Updated examples can be found in the ghcjs-examples repository, or click the source link. The safety specifications in the JavaScript foreign function interface have been changed slightly, see GHCJS.Foreign for more information. In particular, you need "interruptible" instead of "safe" for asynchronous imports.

introduction

After many months of hard work, we are finally ready to show you the new version of GHCJS. Our goal is to provide a full-featured Haskell runtime in the browser, with features like threading, exceptions, weak references and STM, allowing you to run existing libraries with minimal modification. In addition we have some JavaScript-specific features to make communication with the JS world more convenient. GHCJS uses its own package database and comes with Cabal and Template Haskell support.

The new version (gen2) is almost a ground-up rewrite of the older (trampoline/plain) versions. We built on our experience with the trampoline code generator, by Victor Nazarov and Hamish Mackenzie. The most important changes are that we now use regular JavaScript objects to store Haskell heap objects (instead of JS closures), and that we have switched to explicit stacks in a JavaScript array. This helps reduce the amount of memory allocation considerably, making the resulting code run much faster. GHCJS now uses Gershom Bazerman’s JMacro library for generating JavaScript and for the Foreign Function Interface.

This post is a practical introduction to get started with GHCJS. Even though the compiler mostly works now, it’s far from finished. We’d love to hear some feedback from users and get some help preparing libraries for GHCJS before we make our first official release (planned to coincide with the GHC 7.8 release). I have listed some fun projects that you can help us with at the end of this post. Join #ghcjs on freenode for discussion with the developers and other users.

Some highlights of the new version:

  • Easier installation, the compiler is now standalone, with its own package database. Install the compiler with cabal install ghcjs, install packages with cabal install --ghcjs myPackage,
  • Everything works on 64 bit machines, generated JavaScript is the same as on 32 bit,
  • New JavaScript FFI calling convention, with convenient import patterns and asynchronous FFI,
  • Much improved performance compared to the older trampoline version, while still doing full tail-call optimization,
  • Improved threading with black holes, asynchronous exceptions and STM,
  • The scheduler yields during long computations, to keep the browser responsive and able to handle events, even during long calculations,
  • Better and faster Integer/big number support through JSBN,
  • Easier command line testing with Node.js and jsshell,
  • An extensive testsuite with benchmarks (includes much of the GHC testsuite and nofib).

Some work still remains:

  • Cabal support is incomplete, in particular bundling JS files with cabal packages is not yet supported,
  • Our dataflow analyzer needs some more tweaks to make the generated code smaller, also some metadata is currently encoded inefficiently,
  • The front end (ghcjs executable) needs some work, for example to only recompile changed files,
  • The linker is too simple, it only supports linking everything referenced by main to one big file, some improvements, including incremental loading, are planned,
  • Some debug tracing code cannot be fully disabled, making some parts of the RTS run slower than necessary.
  • More optimization is required to increase compilation speed and reduce memory consumption when compiling very heavy packages like haskell-src-exts.
  • Unboxed arrays are implemented with DataView, using big endian byte ordering. Since most clients are little endian, and JavaScript libraries tend to expect native byte order, we are going to switch to typed array views and little endian.

installation

GHCJS depends on a patched GHC HEAD (7.8) to support some of the new improvements, like the javascript calling convention. In addition to that, you need a patched Cabal library and cabal-install which adds the GHCJS compiler flavour. We hope to have these patches merged before the first release in September, but unfortunately that means that it’s not yet possible to just cabal install the compiler.

The easiest way to install GHCJS is with the vagrant setup script from the ghcjs-build repository. This builds a virtual machine with a fully working installation, and includes some examples.

Building is very easy, just run the following commands after installing vagrant:

# git clone https://github.com/ghcjs/ghcjs-build.git
# cd ghcjs-build
# git checkout prebuilt
# vagrant up

This downloads prebuilt binaries from our server. If you want to build everything from source, use this instead (warning, can take 3-4 hours):

# git clone https://github.com/ghcjs/ghcjs-build.git
# cd ghcjs-build
# vagrant up

After the build has finished, log into the newly created virtual machine:

# vagrant ssh

GHCJS should now be installed:

# which ghcjs
/home/vagrant/.cabal/bin/ghcjs

All the examples in the rest of this post are available in /home/vagrant/ghcjs-examples/weblog in the vm, and on github. Exchanging files between the vm and the host is easy: The directory containing the vagrant setup script is mounted under /vagrant in the vm, so just copy files there.

first steps

You can now test the installation by compiling a simple Haskell file:

module Main where

main = putStrLn "Hello, world"

Compile it and run the result with Node.js and jsshell (both preinstalled on vagrant):

# ghcjs -o hello hello.hs
[1 of 1] Compiling Main             ( hello.hs, hello.o )
[1 of 1] Compiling Main
linking hello.jsexe: Main
# node hello.jsexe/all.js
Hello, world
# js hello.jsexe/all.js
Hello, world

The example also works in the browser. You need a web server to run it. The warp server from the warp-static package is very convenient for this. It comes preinstalled on the vagrant vm. Run the following on the host, from the ghcjs-build directory:

# vagrant ssh -c warp

Warp now listens on port 3000 and serves the home directory in the vm. Port 3030 on the host is remapped to this port on the virtal machine, so you should open http://localhost:3030/ on the host to see the examples. You can find the hello example at http://localhost:3030/ghcjs-examples/weblog/hello/hello.jsexe/.

putStrLn will print to the JavaScript debug console in the default configuration (you can redirect the output, but that’s a topic for a later post), so you need to open that first to see the result. Here’s what it should look like in Chrome:

hello world

hello world

GHCJS produces several files when compiling an executable. The most important one is out.js which contains all the compiled Haskell code. The GHCJS linker starts with the main IO action and includes all its (function-level) dependencies in out.js. We have plans to add more options to the linker, including incremental loading. If you have specific needs or wishes, please let us know!

lib.js and lib1.js contain non-Haskell dependencies, including most of the RTS. The contents depend on the packages used by the program: All foreign dependencies of the program are included here. Currently this is done through the yaml descriptions in the shims repository, but we want to add support to Cabal to include the .js files directly in packages. File lists lib.js.files and lib1.js.files are included to support custom build systems, for example if you want to load some of the dependencies from a different location.

rts.js is a static file, generated by the compiler, which has lots of functions used by the Haskell runtime system. It’s the same for every program, but it might change depending on the debug options GHCJS is compiled with.

file description
all.js combined lib.js, lib1.js, out.js, and rts.js, runnable with Node.js and jsshell.
lib.js RTS and non-Haskell functions (this contains most of the RTS, including the scheduler)
lib.js.files list of files in lib.js
lib1.js RTS and non-Haskell functions that must be included after rts.js
lib1.js.files list of files in lib1.js
out.js compiled Haskell code
rts.js JMacro generated part of the RTS
index.html a sample HTML file that runs the main IO action

The HTML file below is the default HTML generated by GHCJS. It runs the main IO action h$mainZCMainzimain (z-encoded main:Main.main prefixed with h$) with h$main, which starts a new thread labeled “main” . The thread is started in the background, h$main returns immediately. The Haskell runtime scheduler is started if it’s not yet running.

You can customize the HTML file, GHCJS does not overwite the file if it already exists.

<!DOCTYPE html>
<html>
  <head>
    <script language="javascript" src="lib.js"></script>
    <script language="javascript" src="rts.js"></script>
    <script language="javascript" src="lib1.js"></script>
    <script language="javascript" src="out.js"></script>
  </head>
  <body>
  </body>
  <script language="javascript">
    
h$main(h$mainZCMainzimain);

  </script>
</html>

foreign function interface

Note: The foreign function interface has been changed and the information below is out of date. You need "interruptible" now for asynchronous imports. See GHCJS.Foreign for more information

One of the improvements in the new GHCJS is support for the new foreign import javascript calling convention. This not only gives us more convenient import patterns, inspired by UHC-JS and Fay, but also asynchronous FFI. foreign import ccall is still supported, for compatibility with existing libraries, which can be used unchanged if you provide JavaScript implementations of the foreign imports.

Let’s look at the next example. If you open it in a browser (http://localhost:3030/ghcjs-examples/weblog/ffi/ffi.jsexe/ if you use the vagrant build) it prints the numbers 1. . 1000 to the document, one number per second.

{-# LANGUAGE JavaScriptFFI, CPP #-}

module Main where

#ifdef __GHCJS__
foreign import javascript unsafe "document.write($1+'<br/>');"
    writeNumber :: Int -> IO ()
foreign import javascript safe   "setTimeout($c, $1);"
    delay       :: Int -> IO ()
#else
writeNumber = error "writeNumber: only available from JavaScript"
delay = error "delay: only available from JavaScript"
#endif

main :: IO ()
main = mapM_ (\x -> writeNumber x >> delay 1000) [1..1000]

writeNumber is a regular, synchronous, import. Placeholder $1 is replaced with the first function argument, an Int. It writes this integer and an HTML linebreak to the document using document.write.

The second import, delay, is an asynchronous import, indicated by the safe specification. An asynchronous imports get a callback parameter $c. The calling Haskell thread is suspended until $c is called, but other Haskell threads and JavaScript code continue to run (and the suspended thread can still receive asynchronous exceptions). This fits nicely into the common JavaScript pattern of doing IO asynchronously, reporting the results with a callback.

In the example, delay uses the JavaScript function setTimeout to call $c after $1 milliseconds, so it works more or less like threadDelay (GHCJS supports threadDelay more efficiently through its own scheduler though). Another example of this pattern can be found in the ghcjs-jquery ajax function.

FFI argument and result types

GHCJS FFI supports the same types as native GHC does for ccall foreign imports, with one addition, the JSRef type, defined in ghcjs-prim. JSRef is used to store arbitrary JavaScript values. When you enable the JavaScriptFFI extension, you can pass JSRef values to both javascript and ccall imports. The ghcjs-base package has some tools to manipulate JSRef values.

The FFI does marshalling for arguments the same way as the native GHC FFI does: If your foreign import has an Int argument, it gets a JavaScript number and not some thunk object.

Most numeric types are represented as a JavaScript number. Since JS doesn’t support single precision floating point, double precision is used everywhere. This can lead to results that differ slightly from GHC’s. If you return an Int or Word value, make sure that it’s an integer that fits in 32 bits. An easy way to do that is to return x|0 instead of x. The bitwise or operator forces the result to be a 32 bit integer.

Some FFI types don’t fit in a single JavaScript variable. For example the JS number type has only 53 bits of precision, not enough for Word64# and Int64#. These types are passed in two arguments with the ccall convention. With the javascript calling convention they get two placeholders, see below for an example.

JavaScript only supports signed 32 bit operands for its bitwise operations. Therefore any Word# value greater than 232 − 1 is represented by a negative number. The same goes for the two words in a Word64# and the least significant word in an Int64#.

Since JavaScript has no pointers, support for Ptr/Addr# is limited: Comparing pointers only works properly for pointers referring to the same data object, only the offsets are compared.

types primitive size JavaScript type
Int, Int32, Int16, Int8 Int# 1 number
Word, Word32, Word16, Word8 Word# 1 number (signed)
Char Char# 1 number
Int64 Int64# 2 number × number
Word64 Word64# 2 number × number
Ptr Addr# 2 object × number
StablePtr StablePtr 2 object × number
Array Array#, MutableArray#, MutableArrayArray# 1 array
UArray, Vector, Text ByteArray#, MutableByteArray# 1 object (DataView)
other MVar#, MutVar#, TVar#, Weak#, ThreadId#, StableName# 1 object
JSRef ByteArray# 1 anything

When using the ccall calling convention, size-two values get passed in two arguments. If you return such a value, store the second part in the special global variable h$ret1.

Both safe and unsafe ccall imports can call back into the Haskell runtime, but ccall imports are always synchronous.

foreign import ccall unsafe "plus"
   plus :: Int -> Int -> Int
foreign import ccall unsafe "complement"
   negate :: Int64 -> Int64
foreign import ccall unsafe "f"
   f :: Ptr a -> IO (Ptr b)

To avoid clashing with existing JavaScript names, all ccall imported functions (like the rest of the GHCJS runtime) are prefixed with h$, which leads to the following JS implementation for the above imports:

function h$plus(x,y) {
  return (x+y)|0;
}

function h$complement(x_msw, x_lsw) {
  h$ret1 = ~x_lsw;
  return ~x_msw;
}

function h$f(x_data, x_offset) {
   ...
   h$ret1 = new_ptr_offset;
   return new_ptr_data;
}

If you use size-two values with the javascript calling convention, you get multiple placeholders, for example $1 and $1_2 ($1_1 also works for the first value). Results are assigned to $r and $r_2.

If the result size is 1, and the foreign import is synchronous, you can import a JavaScript expression and the result will be assigned automatically, like in the sin example below.

Imports are not restricted to simple statements and expressions. You can use loops, local variables and other JavaScript constructs. Thanks to JMacro, local variable names in the import are converted to hygienic names, so you don’t need to worry about existing local variables in the code.

foreign import javascript unsafe
   "$r = f($1, $1_2); $r_2 = h$ret1;"
   g :: Ptr a -> IO (Ptr b)
foreing import javascript unsafe
   "Math.sin($1)" -- the same as "$r = Math.sin($1);"
   sin :: Double -> Double
foreign import javascript unsafe
   "for(var i=0;i<$3;i++) { $1[i] = $2[i]; }"
   copyArray :: JSArray -> JSArray -> Int -> IO ()

See the ghcjs-jquery and ghcjs-canvas packages for more examples of foreign imports.

text and JavaScript strings

It is not possible to pass a Haskell String directly to JavaScript. The best way to do it is to convert the text to a JSString (which is a JSRef) using the classes in GHCJS.Foreign.

toJSString converts the value to Text first, and then converts the underlying UTF-16 ByteArray# buffer to a JavaScript UCS-2 string. This means that working with Text is much faster than working with String.

foreign functions and packages

If your program or library requires some foreign code, the code must be added to the lib.js or lib1.js files for everything that depends on the package (or included in the HTML file manually). Unfortunately it’s not yet possible to include the foreign code in a Cabal package yet (it’s a planned feature).

As a workaround, we have the shims repository. It contains a yaml description file for every package, which references the required JavaScript files. When a package is then used, the files are automatically included in lib.js or lib1.js (in the same order as they are listed in the yaml file). Files referenced by multiple packages are included only once.

Please send us a pull request if you have added GHCJS support for a library. Package-specific support should go into pkg, general functionality to src. lib contains third party JavaScript libraries.

concurrency and exception handling

Threading in GHCJS is implemented in a way similar to the single-threaded GHC runtime: There is one system thread on top of which multiple lightweight Haskell threads run. Long Haskell computations are interleaved by the preemptive scheduler in the runtime system, which also yields occassionally to let the browser run event handlers and other JavaScript code. Since JavaScript does not have shared-memory parallellism, operations like par are no-ops in GHCJS.

Keep in mind that long-running JavaScript computations (called through the FFI or directly outside of Haskell code) will block all Haskell threads, as well as event handling for the browser itself. It’s best to run these things in an incremental way, or to move the whole calculation to a Web Workers process.

Other than this, threading works exactly the same as it does for native code with GHC, including support for MVar, STM (atomically, TVar) and more advanced data structures like Chan and TChan based on those.

The example below (/home/vagrant/ghcjs-examples/weblog/race) starts 10 threads that each update the position of a red square on a “race track”. The call to threadDelay after each update makes the scheduler switch to a new thread immediately, creating a smooth animation. Other than the GUI, which is browser specific, this is exactly how you would write a native Haskell program.

{-# LANGUAGE JavaScriptFFI, CPP #-}
module Main where

import Control.Monad
import Control.Concurrent
import GHCJS.Foreign
import GHCJS.Types

#ifdef __GHCJS__
foreign import javascript unsafe 
  "document.getElementById($1).style.left = '' + $2 + 'px'"
  setPos :: JSString -> Int -> IO ()
#else
setPos = error "setPos: only available in JavaScript"
#endif

main :: IO ()
main = mapM_ runRacer [1..10]

runRacer :: Int -> IO ()
runRacer n = void $ forkIO $ do
  doRace (toJSString $ "racer" ++ show n)

doRace :: JSString -> IO ()
doRace str = go (0::Int)
  where
    go n | n > 800   = go 0
         | otherwise = do
             setPos str n
             threadDelay 1
             go (n+1)

The HTML for this example contains the race track and some extra elements for the red squares:

<html>
  <head>
    <script language="javascript" src="lib.js"></script>
    <script language="javascript" src="rts.js"></script>
    <script language="javascript" src="lib1.js"></script>
    <script language="javascript" src="out.js"></script>
    <style>
      div.track { width: 800px; height: 30px; border: 1px solid black; position: relative }
      div.racer { background-color: rgb(255,0,0); width: 20px; height: 20px; position: absolute; top: 5px }
    </style>
  </head>
  <body>
    <div class=track><div class=racer id=racer1></div></div>
    <div class=track><div class=racer id=racer2></div></div>
    <div class=track><div class=racer id=racer3></div></div>
    <div class=track><div class=racer id=racer4></div></div>
    <div class=track><div class=racer id=racer5></div></div>
    <div class=track><div class=racer id=racer6></div></div>
    <div class=track><div class=racer id=racer7></div></div>
    <div class=track><div class=racer id=racer8></div></div>
    <div class=track><div class=racer id=racer9></div></div>
    <div class=track><div class=racer id=racer10></div></div>
  </body>
  <script language="javascript">
    
h$main(h$mainZCMainzimain);

  </script>  
</html>

exception handling and blackholes

New additions in the latest GHCJS version are support for blackholing and asynchronous exceptions. Blackholes are important for avoiding some kinds of memory leaks, help detect infinite loops (the <<loop>> exception) and prevent duplicate work when multiple threads try to evaluate the same thunk. Asynchronous exceptions are used to interrupt threads during a computation or while waiting on a blocking operation (async foreign call or MVar operation for example).

The example below demonstrates these features. main runs a loop, starting a thread to compute fib38 and print the result. After one second, the main thread throws an asynchronous exception to the forked thread. If the thread hasn’t finished computing and printing fib38 by that time, the running computation is suspended and the exception handler prints “not finished”. The next iteration, the fib38 computation is resumed from where it was interrupted.

Therefore, the example should print “not finished” a few times (depending on the speed of your computer and JavaScript engine). Eventually, the fib38 thunk is updated with the result, so the forked thread will just print the value every time from then on.

{-# LANGUAGE ScopedTypeVariables #-}
module Main where

import           Control.Concurrent
import qualified Control.Exception as E
import           Control.Monad

-- this is inefficient on purpose
fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)

fib38 = fib 38

printFib = print fib38 `E.catch` \(_::E.SomeException) ->
                                      putStrLn "not finished"

main = forever $ do
         tid <- forkIO printFib
         threadDelay 1000000
         throwTo tid E.Overflow

System.Timeout uses the same technique as the example, and also works with GHCJS. Interrupting computations not only works for pure code like fib38, but also for IO operations like asychronous FFI calls and waiting for an MVar.

For more details on black holes, see Runtime Support for Multicore Haskell. GHCJS implements eager blackholing (the default setting for GHC is lazy blackholing), since it has no control over the JS garbage collector.

synchronous threads

The threads we have seen so far were all asynchronous: They are started with h$main or h$run, both of which take an IO action and start a new thread that runs the action in the background. This allows the Haskell runtime to provide asynchronous IO and keep the browser responsive by yielding during long calculations.

Usually this is what we want, but it does have one disadvantage: We cannot get any result back from the call, the Haskell thread might not even have started yet when h$run returns. In most cases this is no problem, since Haskell can call back into JavaScript and we can supply a callback function.

Sometimes we need results immediately though, for example if we want an event to stop propagating from an event handler, we must call event.stopPropagation() before returning from the handler. Clearly, h$run will be of no use if we need to call into Haskell to decide whether to stop propagation of the event.

The alternative is to start the thread with h$runSync, which tries to run the thread to completion before returning. If the thread is not finished before the h$runSync call returns, it throws an exception:

call result
h$runSync(action,false) run action in a synchronous thread, abort the thread if it tries to do an unsupported operation
h$runSync(action,true) run action in a synchronous thread, continue the thread asynchronously after it does an unsupported operation

Unfortunately, synchronous threads have a few limitations due to JavaScript’s single threaded execution model. The most important limitations are listed below:

operation result
block on MVar synchronous thread is interrupted (If the MVar operation does not block, it works as expected).
threadDelay, yield synchronous thread is interrupted.
asynchronous FFI or IO synchronous thread is interrupted.
enter a blackhole from another thread The other thread is continued temporarily to finish computing the blackhole (might switch to other threads if this thread is also waiting for other blackholes). Synchronous thread is interrupted if the other thread tries to do an unsupported operation or has pending async exceptions.
async exception not supported in synchronous threads.

In general it should be predictable whether an action is safe to run in a synchronous thread. Be careful with lazy IO and unsafePerformIO though.

The example below takes a JavaScript object, wrapped in a JSRef, it reads the input from the input property, calculates the factorial, and stores the result in the output property of the same object.

{-# LANGUAGE OverloadedStrings #-}

module Main where

import GHCJS.Types
import GHCJS.Foreign

import Data.Text (Text)
import Control.Applicative
import Text.Read (readMaybe)

main = do
  o <- newObj
  setProp ("input"::Text) ("123"::JSString) o
  factorial o
  r <- getProp ("output"::Text) o
  putStrLn (fromJSString r)

factorial :: JSRef () -> IO ()
factorial ref = do
  x <- fromJSString <$> getProp ("input"::Text) ref
  let r = case readMaybe x of
            Just n | n < 0 || n > 5000 -> "invalid input"
            Just n -> toJSString . show . fact $ n
            Nothing -> "parse error"
  setProp ("output"::Text) r ref
  where
    fact :: Integer -> Integer
    fact n = product [1..n]

Our HTML sets up an event listener for a text field. The event listener builds an IO action by applying the factorial function to a JSRef object, which it then executes in a synchronous thread.

See below for more information about calling Haskell from JavaScript.

<!DOCTYPE html>
<html>
  <head>
    <script language="javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
    <script language="javascript" src="lib.js"></script>
    <script language="javascript" src="rts.js"></script>
    <script language="javascript" src="lib1.js"></script>
    <script language="javascript" src="out.js"></script>
  </head>
  <body>
    <input type="text" id="factorial_input" />
    <div id="factorial_output"></div>
  </body>
  <script language="javascript">

$('#factorial_input').on('keyup change', function(e) {
  var o = { input: $('#factorial_input').val() };
  h$runSync( h$c2( h$ap1_e
                 , h$mainZCMainzifactorial
                 , h$c1(h$ghcjszmprimZCGHCJSziPrimziJSRef_con_e, o)
                 )
           , false
           );
  $('#factorial_output').text(o.output);
});

  </script>
</html>

event handling and the DOM

A straightforward way to handle events is by registering an event handler that runs an IO action. If we run the action in an asynchronous thread, we get no guarantees about the order in which the events are handled, each handler runs independently in its own thread. With a synchronous thread, we would have to be really careful with blocking operations.

That’s why we take a different approach in the ghcjs-jquery package: Instead of starting a new thread to handle each event, we let the (JavaScript) event handler post the event to an MVar. A Haskell thread keeps consuming the events by taking the values from the MVar. This way, all events are always processed in order, and the overhead for processing an event is kept low.

This approach cannot always be used, since no Haskell code can be run to decide whether to stop propagating the event.

Below is a simple example using ghcjs-jquery to handle events, using the MVar approach under the hood:

{-# LANGUAGE OverloadedStrings #-}

module Main where

import JavaScript.JQuery
import JavaScript.JQuery.Internal
import Data.Default
import qualified Data.Text as T

main = do
  b <- select "body"
  append "<div class='mouse'></div>" b
  m <- select ".mouse"
  mousemove (handler m) def b

handler :: JQuery -> Event -> IO ()
handler m e = do
  x <- pageX e
  y <- pageY e
  setText (T.pack $ show (x,y)) m
  return ()

And the HTML:

<!DOCTYPE html>
<html>
  <head>
    <script language="javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
    <script language="javascript" src="lib.js"></script>
    <script language="javascript" src="rts.js"></script>
    <script language="javascript" src="lib1.js"></script>
    <script language="javascript" src="out.js"></script>
    <style>html,body { height: 100%; padding: 0px; margin: 0px; }</style>
  </head>
  <body>
  </body>
  <script language="javascript">

h$main(h$mainZCMainzimain);

  </script>
</html>

calling Haskell from JavaScript

The current API for calling Haskell from JavaScript is a bit primitive, this section will be updated when the API has been polished a bit more.

We have three functions that can run an IO action:

function result
h$run run the IO action in a new asynchronous thread.
h$main run the IO action in a new asynchronous thread labeled “main”. In Node.js and jsshell, the application exits when this thread finishes.
h$runSync run a synchronous thread

If you don’t have an IO action, but a function that produces one, you can use the following method to apply the function:

x :: Int -> JSRef a -> IO ()
var x = 5;
var y = h$c1(h$ghcjszmprimZCGHCJSziPrimziJSRef_con_e, o)
var action = h$c3(h$ap2_e, h$MainZCMainzix, x, y);
h$runSync(action, false);

The first argument, x is an Int, which can be passed directly to the Haskell function without additional wrapping. The second argument is a JSRef, which is constructed with the h$c1 function, producing a Haskell heap object with one field. The IO action is then created with h$c3 and h$ap2_e, creating a thunk that applies the h$MainZCMainzix function to the two arguments.

Since we work with Haskell data structures directly here, without going through the FFI, we often have to wrap arguments in a Haskell heap object. Some argument types can be passed directly though, like x in the example. Here is a list of types, and how they should be wrapped:

type wrapping
Int, Int8, Int16, Int32, Word, Word8, Word16, Word32, Char, Double, Float Pass directly as a JavaScript number. Make sure that the number is a 32 bit signed integer for the integral types. All datatypes with one constructor and one Int#, Word# or Char# field should be passed this way,
Bool Pass directly as false or true,
Enumerations Enumeration ADTs: multiple constructors without fields. Use the constructors directly, or false, true for the first two constructors, respectively,
primitive types No wrapping is needed, but make sure you use the right apply functions for size-2 values,
everything else wrap in a Haskell heap object, using the h$c functions.

tasks and projects, help needed!

Here are some ideas for if you want to help us with the compiler and libraries. We also have some bigger projects going on. For example Dan Frumin is working on a pastebin site using diagrams and GHCJS to generate interactive widgets for Google Summer of Code. Hamish Mackenzie is working on JavaScriptCore and webkit binding to make building cross-platform applications that can run in the browser (with GHCJS) or in native code (with webkitgtk for the GUI) with minimal changes.

Contact us in #ghcjs on freenode for more project ideas, or if you want some pointers to work on the GHCJS core itself.

project description
break it! if you find something that doesn’t work as expected, please report the bug. a minimal testcase that we can add to our testsuite would be awesome (should run with Node.js and jsshell, print deterministic results to stdout)
tell us what features or changes you need join us in #ghcjs on freenode, or create a ticket on github. In particular ideas that might need a change to the GHC patch should be reported quickly, we don’t want to be too late to merge in GHC 7.8!
make your favourite Haskell library work with GHCJS submit implementations of foreign functions required by your lib (or dependencies) to the (shims)[https://github.com/ghcjs/shims] repository
make bindings for your favourite JavaScript library or API See ghcjs-canvas and ghcjs-jquery for examples.
extend the Cabal patch to support bundling and installing .js files with packages We can install packages with cabal install --ghcjs package, but JavaScript files cannot be installed and linked automatically yet. Add some fields to the .cabal file format for this, and make sure that they get installed correctly.
more DOM support in ghcjs-base Add a new module with DOM functions like getElementById to ghcjs-base.
split the gloss package Gloss works with GHCJS, (examples: zen tree styrene lens pong ) we have a backend that draws on a Canvas, but the package depends on OpenGL, which makes installation more difficult. Split Gloss into an OpenGL part (gloss) and a non-OpenGL part (gloss-base) to make installation with GHCJS easier.
Web GUI framework bindings Make a high-level Web GUI library, either doing low-level DOM directly, or by binding an existing GUI library like YUI or jQuery-UI
FRP GUI bindings FRP libraries like sodium or reactive-banana run out of the box, or with minor changes, with GHCJS, but we don’t have a convenient way to set up a reactive user interface yet.
a better stepeval/debugger we have a few examples showing the heap and stack when reducing a computation with step by step: ghcjs reduce. It would be nice to add a user interface to step through the evaluation, and to be able to interact more with the objects on the heap/stack (expanding/collapsing the view of the objects, changing the values)