1 | | // A computation describes a way to compute a value out of the environment. |
2 | | // The value may not immediately be available (eg. if it's being asynchronously |
3 | | // fetched from a server). |
4 | 1 | var Computation = (function () { |
5 | | function Computation(fn) { |
6 | 14 | this.fn = fn; |
7 | | } |
8 | | // Convenience functions to create pure and failing computations. |
9 | 1 | Computation.pure = function (value) { |
10 | 2 | return new Computation(function () { |
11 | 10 | return value; |
12 | | }); |
13 | | }; |
14 | 1 | Computation.fail = function (e) { |
15 | 2 | return new Computation(function () { |
16 | 5 | throw e; |
17 | | }); |
18 | | }; |
19 | | |
20 | | // Like the ES6 Promise#then function. |
21 | 1 | Computation.prototype.then = function (resolve, reject) { |
22 | 8 | var _this = this; |
23 | 8 | return new Computation(function () { |
24 | 8 | try { |
25 | 8 | return resolve(_this.fn()); |
26 | | } catch (e) { |
27 | 4 | if (reject) { |
28 | 1 | return reject(e); |
29 | | } else { |
30 | 3 | throw e; |
31 | | } |
32 | | } |
33 | | }); |
34 | | }; |
35 | | |
36 | | // Map over the result. Pending state and errors are passsed onto the next |
37 | | // computation untounched. |
38 | 1 | Computation.prototype.fmap = function (f) { |
39 | 5 | return this.then(function (v) { |
40 | 5 | if (v === Computation.Pending) { |
41 | 1 | return Computation.Pending; |
42 | | } else { |
43 | 4 | return f(v); |
44 | | } |
45 | | }); |
46 | | }; |
47 | | |
48 | | // Like fmap, but the function can return a computation which is then |
49 | | // automatically executed. |
50 | 1 | Computation.prototype.bind = function (f) { |
51 | 3 | return this.fmap(function (v) { |
52 | 3 | return f(v).fn(); |
53 | | }); |
54 | | }; |
55 | | |
56 | | // Pending computations and errors are passed through. |
57 | 1 | Computation.liftA2 = function (a, b, f) { |
58 | 3 | try { |
59 | 3 | var av = a.fn(), bv = b.fn(); |
60 | | |
61 | 2 | if (av !== Computation.Pending && bv !== Computation.Pending) { |
62 | 1 | return new Computation(function () { |
63 | 1 | return f(av, bv); |
64 | | }); |
65 | | } else { |
66 | 1 | return Computation.pending; |
67 | | } |
68 | | } catch (e) { |
69 | 1 | return Computation.fail(e); |
70 | | } |
71 | | }; |
72 | | |
73 | | // Get the result of this computation. If the result is not available yet, |
74 | | // return the fallback value. |
75 | 1 | Computation.prototype.get = function (fallback) { |
76 | 14 | try { |
77 | 14 | var result = this.fn(); |
78 | 9 | if (result === Computation.Pending) { |
79 | 3 | return fallback; |
80 | | } else { |
81 | 6 | return result; |
82 | | } |
83 | | } catch (e) { |
84 | 5 | return fallback; |
85 | | } |
86 | | }; |
87 | 1 | Computation.Pending = {}; |
88 | | |
89 | 1 | Computation.pending = new Computation(function () { |
90 | 4 | return Computation.Pending; |
91 | | }); |
92 | 1 | return Computation; |
93 | | })(); |
94 | | |
95 | 1 | if (typeof module !== 'undefined') { |
96 | 1 | module.exports = Computation; |
97 | | } |
98 | | |