packages feed

ghcjs-base-stub-0.3.0.1: ghcjs-base/README.md

# Introduction to ghcjs-base

It is a minimal low-level base library for GHCJS, used by higher level
libraries like JSC

It contains modules for 

* Marshalling from and to Javascript in `GHCJS/`
* Javascript API in `JavaScript/`

# Marshalling from and to Javascript

This section assumes you read *GHCJS foreign function interface* which you can find on *ghcjs/ghcjs*.

### Representation of Javascript Types in GHCJS

#### Arbitrary Javascript Value

Arbitrary javascript values are represented by `GHCJS.Types.JSVal`

```haskell
import GHCJS.Types (JSVal)

foreign import javascript unsafe
  "$1 + $2" add :: JSVal -> Int -> JSVal

foreign import javascript unsafe
  "require($1)" require :: JSVal -> JSVal
```

Internally, `JSVal` is defined as

```haskell
data JSVal = JSVal ByteArray#
```

But, it is an implementation detail you should not have to care about in most cases.

#### Javascript String

It is defined in `Data.JSString` as

```haskell
newtype JSString = JSString JSVal
```

`JSString` is also available from `GHCJS.Types`.

#### TypedArray

If you already knew how to use TypedArray, understanding `JavaScript.TypedArray`
would not be difficult.

#### ArrayBuffer

It is represented by `JavaScript.TypedArray.ArrayBuffer`.
`GHCJS.Buffer` is an obsolete implementation of ArrayBuffer.

### Conversion among Javascript Types

It seems people use `unsafeCoerce` from `Unsafe.Coerce` to convert `JSVal` to other Javascript types and vice versa. There is `JavaScript.Cast`, but it is considered incomplete.

### Conversion between Haskell String and Javascript String

`Data.JSString` contains

```haskell
pack :: String -> JSString
unpack :: JSString -> String
```

Use them as in the following example.

```haskell
import Data.JSString as S

foreign import javascript unsafe
  "require('console').log($1)" console_log :: S.JSString -> IO ()

main :: IO ()
main = do
  let message = "yo" :: String
  console_log (S.pack message)
```

### Pass Haskell String Literals as Javascript String

`Data.JSString` contains `instance IsString JSString`, so it's possible to write

```haskell
import Data.JSString as S

foreign import javascript unsafe
  "require('console').log($1)" console_log :: S.JSString -> IO ()

main :: IO ()
main = do
  console_log "yo"
```

### Marshalling Arbitrary Types from and to Javascript

GHCJS FFI by itself cannot marshal a lot of types from and to `JSVal`. If you want to convert `JSVal` into such types, you need to make wrapper functions that call foreign functions, convert the result to a value of the desired type, and return the converted value. Here is a minimal example.

```haskell
foreign import javascript unsafe
  "$1 === 0" js_isEqualToZero :: Int -> Bool

data NewBool = Yes | No

isEqualToZero :: Int -> NewBool
isEqualToZero n = if js_isEqualToZero n then Yes else No
```

#### Pure Marshalling

If the conversion from and to `JSVal` doesn't involve side effects, you can use pure marshalling API.
`GHCJS.Marshal.Pure` exports

```haskell
class PToJSVal a where
  pToJSVal :: a -> JSVal

class PFromJSVal a where
  pFromJSVal :: JSVal -> a
```

`GHCJS.Marshal.Pure` has `PFromJSVal` and `PToJSVal` instances for various basic types.

#### Impure Marshalling

If the conversion from and to `JSVal` involves side effects or doesn't return
the same output every time for the same input, you may want to use
`GHCJS.Marshal`. `GHCJS.Marshal` exports

```haskell
import qualified Data.Aeson as AE

toJSVal_aeson :: AE.ToJSON a => a -> IO JSVal
toJSVal_pure :: PToJSVal a => a -> IO JSVal

class ToJSVal a where
  toJSVal :: a -> IO JSVal
  -- other functions are omitted for simplicity

class FromJSVal a where
  fromJSVal :: JSVal -> IO (Maybe a)
  -- other functions are omitted for simplicity
```

As far as I know, since `FromJSVal` and `ToJSVal` are generic typeclasses, you can use Generics to derive instances for `FromJSVal` and `ToJSVal` without boiler plates if you know how to use Generics.

#### `Maybe` in Javascript Functions

If you want to express `Maybe` in imported foreign functions, use `GHCJS.Nullable`. `Nullable` is defined in `GHCJS.Nullable` as

```haskell
newtype Nullable = Nullable JSVal
```

It is simply a newtype wrapper around `JSVal`. The following functions turn `Nullable` into something more than a mere newtype wrapper around `JSVal`.
`GHCJS.Nullable` exports

```haskell
nullableToMaybe :: PFromJSVal a => Nullable a -> Maybe a
maybeToNullable :: PToJSVal a => Maybe a -> Nullable a
```

The type signatures of those function make it clear that you need to implement pure marshalling typeclasses if you want to marshal `Maybe`.

You can use `Nullable` as below.

```haskell
import GHCJS.Nullable

foreign import javascript unsafe
  "if($1 === 0) { $r = null; } else { $r=$1; }"
  js_nullIfZero :: Int -> Nullable Int

maybeZero :: Int -> Maybe Int
maybeZero n = nullableToMaybe (js_nullIfZero n)
```

In the above example, I didn't need `instance PFromJSVal Int` because it is already implemented in `GHCJS.Marshal.Pure`. As stated before, `GHCJS.Marshal.Pure` has `PFromJSVal` and `PToJSVal` instances for many basic types.

### Passing Haskell Callbacks to Javascript

With `GHCJS.Foreign.Callback`, you can create callbacks that you can pass to imported javascript functions. `Callback` is defined as

```haskell
newtype Callback a = Callback JSVal
```

It's just a newtype wrapper around `JSVal`. There are currently two kinds of callbacks, synchronous callbacks and asynchronous callbacks.

#### Asynchronous Callbacks

Asynchronous callbacks are simpler than synchronous callbacks. If an synchronous callback is passed to a javascript function and the function calls the callback, the callback launches an asynchronous haskell thread. Let's look at the functions that generate asynchronous callbacks.

```haskell
asyncCallback :: IO () -> IO (Callback (IO ()))
asyncCallback1 :: (JSVal -> IO ()) -> IO (Callback (JSVal -> IO ()))
asyncCallback2 :: (JSVal -> JSVal -> IO ())
               -> IO (Callback (JSVal -> JSVal -> IO ()))

-- There is also asyncCallback3
```

`asyncCallback` accepts an IO action and returns a callback in `IO`. `asyncCallback1` returns a callback that accepts one argument. `asyncCallback2` for a callback of 2 arguments. You can guess what `asyncCallback3` is for.

#### Synchronous Callbacks

When a synchronous callback is called in javascript, it launches a new synchronous thread. There are two kinds of synchronous callback.

* Synchronous callback that throws `GHCJS.Concurrent.WouldBlockException` when its thread blocks
* One that becomes asynchronous when the thread blocks

Let's look at the functions that generate synchronous callbacks.

```haskell
syncCallback :: OnBlocked -- ^ what to do when the thread blocks
             -> IO () -- ^ the Haskell action
             -> IO (Callback (IO ())) -- ^ the callback
```

It's almost the same as `asyncCallback` except the argument for `OnBlocked`. `OnBlocked` is defined in `GHCJS.Concurrent` as

```haskell
data OnBlocked = ContinueAsync -- ^ continue the thread asynchronously if blocked
               | ThrowWouldBlock -- ^ throw 'WouldBlockException' if blocked
               deriving (Data, Typeable, Enum, Show, Eq, Ord)
```

You can guess what `syncCallback1`, `syncCallback2`, and `syncCallback3` do.

`syncCallback'`, `syncCallback1'`, and so on generate synchronous callbacks that throw `WouldBlockException` when their threads block. It's the same as `syncCallback ThrowWouldBlock`, `syncCallback1 ThrowWouldBlock`, and so on.

#### An Example of Using Callback in NodeJs

```haskell
import GHCJS.Foreign.Callback
import Data.JSString -- This includes an IsString instance for JSString
import GHCJS.Types (JSVal)

foreign import javascript unsafe
  "require('console').log($1)" js_consoleLog :: JSVal -> IO ()

foreign import javascript unsafe
  "require('fs').stat($1, $2)"
  js_fsStat :: JSString -> Callback (JSVal -> JSVal -> IO ()) -> IO ()

main :: IO ()
main = do
  cb <- asyncCallback2 $ \err stat -> js_consoleLog stat
  js_fsStat "/home" cb
  releaseCallback cb
```

#### Caveats on Callbacks

* All callbacks should be manually released from memory by `releaseCallback` later.

### How can Arbitrary Haskell Value be stored in and retrieved from Javascript Data Structures?

For example, if you wanted arbitrary haskell data structures to be stored in and retrieved from javascript hashmap, 
`GHCJS.Foreign.Export` should be used. `GHCJS.Foreign.Export` exports

```haskell
newtype Export a = Export JSVal

export :: Typeable a => a -> IO (Export a)
withExport :: Typeable a => a -> (Export a -> IO b) -> IO b
derefExport :: forall a. Typeable a => Export a -> IO (Maybe a)
releaseExport :: Export a -> IO ()
```

* `export` : exports an arbitrary haskell data structure as a blob of javascript value. Since `Export a` is actually `JSVal`, `Export a` can be passed to and retrieved from javascript data structures such as hashmap.
* `releaseExport` : releases all memory associated with the export. Subsequent calls to 'derefExport' will return 'Nothing'
* `derefExport` : retrieves the haskell value from an export. It returns 'Nothing' if the type does not match or the export has already been released.
* `withExport` : exports a given value, runs the action `IO b`, and returns `IO b`. The value is only exported for the duration of the action. Dereferencing it after the `withExport` call has returned will always return `Nothing`.

### Various Utilities for Javascript

`GHCJS.Foreign` exports `jsTrue`, `jsFalse`, `jsNull`, `isTruthy`, `isString`, `isBoolean`, etc, ... You can inspect those functions and understand them easily.

# Javascript API

If you already knew javascript APIs, it wouldn't be difficult to inspect and understand `JavaScript.Object`, `JavaScript.Array`, `JavaScript.String`, `JavaScript.RegExp`, etc, ...