1 | var interfaces = {
|
2 | semigroup: ['concat'],
|
3 | monoid: ['concat', 'empty'],
|
4 | functor: ['map'],
|
5 | apply: ['map', 'ap'],
|
6 | applicative: ['map', 'ap', 'of'],
|
7 | chain: ['map', 'ap', 'chain'],
|
8 | monad: ['map', 'ap', 'chain', 'of'],
|
9 | extend: ['extend'],
|
10 | comonad: ['extend', 'extract'],
|
11 | foldable: ['reduce'],
|
12 | transformer: ['lift']
|
13 | };
|
14 |
|
15 | var Identity = require('..').Identity;
|
16 |
|
17 | function correctInterface(type) {
|
18 | return function(obj) {
|
19 | return interfaces[type].every(function(method) {
|
20 | return obj[method] && typeof obj[method] === 'function';
|
21 | });
|
22 | };
|
23 | }
|
24 |
|
25 | function identity(x) { return x; }
|
26 |
|
27 | module.exports = function(eq) {
|
28 | return {
|
29 | semigroup: {
|
30 | iface: correctInterface('semigroup'),
|
31 | associative: function (a, b, c) {
|
32 | return eq(a.concat(b).concat(c), a.concat(b.concat(c)));
|
33 | }
|
34 | },
|
35 |
|
36 | functor: {
|
37 | iface: correctInterface('functor'),
|
38 | id: function (obj) {
|
39 | return eq(obj, obj.map(identity));
|
40 | },
|
41 | compose: function (obj, f, g) {
|
42 | return eq(
|
43 | obj.map(function (x) {
|
44 | return f(g(x));
|
45 | }),
|
46 | obj.map(g).map(f)
|
47 | );
|
48 | }
|
49 | },
|
50 |
|
51 | apply: {
|
52 | iface: correctInterface('apply'),
|
53 | compose: function (a, u, v) {
|
54 | return eq(
|
55 | a.ap(u.ap(v)),
|
56 | a.map(function (f) {
|
57 | return function (g) {
|
58 | return function (x) {
|
59 | return f(g(x));
|
60 | };
|
61 | };
|
62 | }).ap(u).ap(v)
|
63 | );
|
64 | }
|
65 | },
|
66 |
|
67 | applicative: {
|
68 | iface: correctInterface('applicative'),
|
69 | id: function (obj, obj2) {
|
70 | return eq(obj.of(identity).ap(obj2), obj2);
|
71 | },
|
72 | homomorphic: function (obj, f, x) {
|
73 | return eq(obj.of(f).ap(obj.of(x)), obj.of(f(x)));
|
74 | },
|
75 | interchange: function (obj1, obj2, x) {
|
76 | return eq(
|
77 | obj2.ap(obj1.of(x)),
|
78 | obj1.of(function (f) {
|
79 | return f(x);
|
80 | }).ap(obj2)
|
81 | );
|
82 | }
|
83 | },
|
84 |
|
85 | chain: {
|
86 | iface: correctInterface('chain'),
|
87 | associative: function (obj, f, g) {
|
88 | return eq(
|
89 | obj.chain(f).chain(g),
|
90 | obj.chain(function (x) {
|
91 | return f(x).chain(g);
|
92 | })
|
93 | );
|
94 | }
|
95 | },
|
96 |
|
97 | monad: {
|
98 | iface: correctInterface('monad')
|
99 | },
|
100 |
|
101 | extend: {
|
102 | iface: correctInterface('extend'),
|
103 | associative: function(obj, f, g) {
|
104 | return eq(
|
105 | obj.extend(g).extend(f),
|
106 | obj.extend(function(_obj) {
|
107 | return f(_obj.extend(g));
|
108 | })
|
109 | );
|
110 | }
|
111 | },
|
112 |
|
113 | comonad: {
|
114 | iface: correctInterface('comonad'),
|
115 | leftIdentity: function (obj) {
|
116 | return eq(obj.extend(function(_obj) { return _obj.extract(); }), obj);
|
117 | },
|
118 | rightIdentity: function (obj, f) {
|
119 | return eq(obj.extend(f).extract(), f(obj));
|
120 | }
|
121 | },
|
122 |
|
123 | foldable: {
|
124 | iface: correctInterface('foldable')
|
125 | },
|
126 |
|
127 | transformer: {
|
128 | iface: function (T) {
|
129 | return correctInterface('transformer')(T(Identity)) &&
|
130 | correctInterface('monad')(T(Identity)(identity));
|
131 | },
|
132 | id: function (transformer) {
|
133 | var T = transformer(Identity);
|
134 | return eq(T.lift(Identity.of(1)), T.of(1));
|
135 | },
|
136 | associative: function (transformer) {
|
137 | var T = transformer(Identity);
|
138 | var m = Identity(1);
|
139 | var f = function (x) {
|
140 | return Identity(x * x);
|
141 | };
|
142 | return eq(
|
143 | T.lift(m.chain(f)),
|
144 | T.lift(m).chain(function (x) {
|
145 | return T.lift(f(x));
|
146 | })
|
147 | );
|
148 | }
|
149 | }
|
150 | };
|
151 | };
|