1
2class Monad {
3 // pure :: a -> M a
4 pure = () => { throw "pure method needs to be implemented" }
5
6 // flatMap :: # M a -> (a -> M b) -> M b
7 flatMap = (x) => { throw "flatMap method needs to be implemented" }
8
9 // map :: # M a -> (a -> b) -> M b
10 map = f => this.flatMap(x => new this.pure(f(x)))
11}
12
13export class Option extends Monad {
14 // pure :: a -> Option a
15 pure = (value) => {
16 if ((value === null) || (value === undefined)) {
17 return none;
18 }
19 return new Some(value)
20 }
21
22 // flatMap :: # Option a -> (a -> Option b) -> Option b
23 flatMap = f =>
24 this.constructor.name === 'None' ?
25 none :
26 f(this.value)
27
28 // equals :: # M a -> M a -> boolean
29 equals = (x) => this.toString() === x.toString()
30}
31
32class None extends Option {
33 toString() {
34 return 'None';
35 }
36}
37// Cached None class value
38export const none = new None()
39Option.pure = none.pure
40
41export class Some extends Option {
42 constructor(value) {
43 super();
44 this.value = value;
45 }
46
47 toString() {
48 return `Some(${this.value})`
49 }
50}
51