-
Notifications
You must be signed in to change notification settings - Fork 0
/
maybe-monad.js
79 lines (64 loc) · 2.25 KB
/
maybe-monad.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/**
* https://www.codewars.com/kata/52793ed3fdb8e19406000c72
*/
let tests = require('./lib/framework.js');
let Test = tests.Test, describe = tests.describe, it = tests.it, before = tests.before, after = tests.after;
/////////////////////////////////////////////////////////////////
function Maybe() {
}
/////////////////////////////////////////////////////////////////
function Just(x) {
//console.log(x);
this.toString = function () { return "Just " + x.toString(); };
this.just = x;
}
Just.prototype = new Maybe();
Just.prototype.constructor = Just;
/////////////////////////////////////////////////////////////////
function Nothing() {
this.toString = function () { return "Nothing"; };
Object.freeze(this);
}
Nothing.prototype = new Maybe();
Nothing.prototype.constructor = Nothing;
/////////////////////////////////////////////////////////////////
// return a Maybe that holds x
Maybe.unit = function (x) {
return new Just(x);
};
// given a function from a value to a Maybe return a function from a Maybe to a Maybe
Maybe.bind = function (f) {
return function (m) {
if (!(m instanceof Maybe)) {
throw new Error('Input is not a Maybe subclass instance')
}
if (m instanceof Just) {
return f(m.just);
} else {
return new Nothing();
}
};
};
// given a function from value to value, return a function from value to Maybe
// if f throws an exception, (lift f) should return a Nothing
Maybe.lift = function (f) {
return function (x) {
try {
return new Just(f(x));
} catch (e) {
return new Nothing();
}
};
};
// given a Maybe m and some functions fns, run m into the first function,
// pass that result to the second function, etc. and return the last result
Maybe.do = function(m) {
var fns = Array.prototype.slice.call(arguments, 1);
return fns.reduce(function (carry, fn) {
return Maybe.bind(fn)(carry);
}, m);
};
let mDup = Maybe.lift( function (s) { return s + s; } );
let mTrim = Maybe.lift( function (s) { return s.replace(/\s+$/, ''); } );
let result = Maybe.do( Maybe.unit('abc '), mDup, mTrim, mDup ); // => new Just "abc abcabc abc"
Test.expect(result.toString() === 'Just abc abcabc abc');