1 | /* @flow weak */
|
2 | ;
|
3 |
|
4 | /**
|
5 | #### isPromise p : bool
|
6 |
|
7 | Optimistic duck-type check for promises.
|
8 | Returns `true` if p is an object with `.then` function property.
|
9 | */
|
10 | function isPromise(p) {
|
11 | /* eslint-disable no-new-object */
|
12 | return new Object(p) === p && typeof p.then === "function";
|
13 | /* eslint-enable non-new-object */
|
14 | }
|
15 |
|
16 | /**
|
17 | #### map (Functor f) => (p : f a) (g : a -> b) : f b
|
18 |
|
19 | This is functor map, known as `map` or `fmap`.
|
20 | Essentially `f(p)`. If `p` is promise, returns new promise.
|
21 | Using `map` makes code look very much [CPS-style](http://en.wikipedia.org/wiki/Continuation-passing_style).
|
22 | */
|
23 | function map(p, g) {
|
24 | if (isPromise(p)) {
|
25 | return p.then(g);
|
26 | } else {
|
27 | return g(p);
|
28 | }
|
29 | }
|
30 |
|
31 | /**
|
32 | #### bind (Functor f) => (k : a -> f b) (xs : a) (h : b -> f c) -> f c
|
33 |
|
34 | This is almost monadic bind.
|
35 | */
|
36 | function bind(f, xs, h) {
|
37 | var r;
|
38 | var exc;
|
39 | try {
|
40 | r = f.apply(undefined, xs);
|
41 | } catch (e) {
|
42 | r = false;
|
43 | exc = e;
|
44 | }
|
45 |
|
46 | if (isPromise(r)) {
|
47 | return r.then(
|
48 | h,
|
49 | function (e) {
|
50 | // exc is always unset here
|
51 | return h(false, e);
|
52 | }
|
53 | );
|
54 | } else {
|
55 | return h(r, exc);
|
56 | }
|
57 | }
|
58 |
|
59 | module.exports = {
|
60 | isPromise: isPromise,
|
61 | map: map,
|
62 | bind: bind,
|
63 | };
|