# 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, ...