paf31 / purescript-promises

An alternative effect monad for PureScript.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

purescript-promises

Build Status

An alternative effect monad for PureScript.

Use this for easy interop with existing promise-based JavaScript libraries.

Usage

With monadic do notation, or with promise-chaining notation. The following are equivalent:

myApply :: forall r a b. Promise r (a -> b) -> Promise r a -> Promise r b
myApply pab pa = do
  ab <- pab
  a <- pa
  pure (ab a)

myApplyChained :: forall r a b. Promise r (a -> b) -> Promise r a -> Promise r b
myApplyChained pab pa = pab # then' \ ab -> pa # then' \ a -> resolve (ab a)

in fact, if you squint a little, myApplyChained looks like the following JavaScript:

var myApplyChained = function (pab, pa) {
  pab.then(function (ab) {
    pa.then(function (a) {
      return Promise.resolve(ab(a));
    });
  });
}

Also see the tests folder.

eagerness

While promises are eager, this library provides the Deferred typeclass to ensure promises don't prematurely run their side-effects until safely consumed with runPromise, or the nonstandard done.

In fact, not only are promises eager, but they're eager about being eager. They really want to run:

delay example

promDelay :: Deferred => Promise AppEff Unit
promDelay = do
  p1
  p2
  p3
  where
    p1 = do
      Console.log "one"
      Promise.delay (Milliseconds 1000.0) unit
      Console.log "two"
    p2 = do
      Promise.delay (Milliseconds 1000.0) unit
      Console.log "three"
    p3 = do
      Promise.delay (Milliseconds 1000.0) unit
      Console.log "four"

this will output one, wait one second, then four three two. In order to obtain the desired behavior of waiting one second between each log, it's necessary to add type annotations to p1, p2 and p3:

p1 :: Deferred => Promise AppEff Unit
p1 = do ...

parallel (<*>)

promApply :: Deferred => Promise AppEff Unit
promApply = p1 *> p2 *> p3
  where
    p1 :: Deferred => Promise AppEff Unit
    p1 = do
      Console.log "<*> is"
      Promise.delay (Milliseconds 1000.0) unit
      Console.log "done"
    p2 :: Deferred => Promise AppEff Unit
    p2 = do
      Promise.delay (Milliseconds 3000.0) unit
      Console.log "parallel"
    p3 :: Deferred => Promise AppEff Unit
    p3 = do
      Promise.delay (Milliseconds 2000.0) unit
      Console.log "in"

Note that difference (between this example and the last) that we're using (*>) instead of implicit (>>=)s. And even though we added the Deferred constraint, it will still take 3 seconds to run total -- not 6, as it would be using do notation.

FFI example

exports.myPromise = new Promise(function (resolve, reject) {
  resolve(5);
});
foreign import myPromise :: forall r. Promise r Int

doSomething :: Deferred => Promise (console :: CONSOLE | r) Unit
doSomething = do
  p <- myPromise
  Console.logShow p

main :: forall r. Eff (console :: CONSOLE | r) Unit  
main
  = runPromise
    (const (log "success callback"))
    (const (error "error callback"))
    doSomething

Installation

bower install --save purescript-promises

See also

About

An alternative effect monad for PureScript.

License:MIT License


Languages

Language:PureScript 83.4%Language:JavaScript 16.6%