UNPKG

1.74 kBJavaScriptView Raw
1/* @flow weak */
2"use strict";
3
4var trampa = require("trampa");
5
6/**
7 #### isPromise p : bool
8
9 Optimistic duck-type check for promises.
10 Returns `true` if p is an object with `.then` function property.
11*/
12function isPromise(p) {
13 /* eslint-disable no-new-object */
14 return new Object(p) === p && typeof p.then === "function";
15 /* eslint-enable non-new-object */
16}
17
18/**
19 #### map (Functor f) => (p : f a) (g : a -> b) : f b
20
21 This is functor map, known as `map` or `fmap`.
22 Essentially `f(p)`. If `p` is promise, returns new promise.
23 Using `map` makes code look very much [CPS-style](http://en.wikipedia.org/wiki/Continuation-passing_style).
24*/
25function map(p, g) {
26 if (isPromise(p)) {
27 return p.then(function (x) {
28 return map(x, g);
29 });
30 } else if (trampa.isTrampoline(p)) {
31 return p.jump(function (x) {
32 return map(x, g);
33 });
34 } else {
35 return g(p);
36 }
37}
38
39/**
40 #### bind (Functor f) => (k : a -> f b) (xs : a) (h : b -> f c) -> f c
41
42 This is almost monadic bind.
43*/
44function bind(f, xs, h) {
45 var r;
46 var exc;
47 try {
48 r = f.apply(undefined, xs);
49 } catch (e) {
50 r = false;
51 exc = e;
52 }
53
54 if (isPromise(r)) {
55 return r.then(
56 h,
57 function (e) {
58 // exc is always unset here
59 return h(false, e);
60 }
61 );
62 } else {
63 return h(r, exc);
64 }
65}
66
67// recursively unwrap trampoline and promises
68function run(x) {
69 if (isPromise(x)) {
70 return x.then(run);
71 } else if (trampa.isTrampoline(x)) {
72 return run(x.run());
73 } else {
74 return x;
75 }
76}
77
78function pure(x) {
79 if (isPromise(x)) {
80 return x;
81 } else {
82 return trampa.wrap(x);
83 }
84}
85
86module.exports = {
87 isPromise: isPromise,
88 map: map,
89 pure: pure,
90 bind: bind,
91 run: run,
92};