├── .config
├── .eslintrc.json
├── .gitignore
├── .npmrc
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── figures
├── dependencies.dot
└── dependencies.sh
├── implementations.md
├── index.d.ts
├── index.js
├── index.mjs
├── logo.png
├── names
├── package.json
├── scripts
├── generate-es
├── generate-js
├── generate-readme
├── generate-ts
└── lint
└── test
├── index.js
└── mocha.opts
/.config:
--------------------------------------------------------------------------------
1 | repo-owner = fantasyland
2 | repo-name = fantasy-land
3 | author-name = Fantasy Land
4 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "extends": ["./node_modules/sanctuary-style/eslint-es3.json"],
4 | "overrides": [
5 | {
6 | "files": "README.md",
7 | "rules": {
8 | "func-call-spacing": ["error", "never"],
9 | "max-len": ["off"],
10 | "no-undef": ["off"],
11 | "no-unused-vars": ["off"]
12 | }
13 | }
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.nyc_output/
2 | /coverage/
3 | /node_modules/
4 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | sudo: false
3 | node_js:
4 | - "6"
5 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Additions and modifications to the specification are best proposed in issues.
4 | If there is support for a proposal, the next step is to submit a pull request.
5 |
6 | When adding a type class to __README.md__, please update __names__ then run:
7 |
8 | ```console
9 | $ npm run generate-js
10 | $ npm run generate-ts
11 | $ npm run generate-es
12 | ```
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2022 Fantasy Land
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Fantasy Land Specification
2 |
3 | [](https://travis-ci.org/fantasyland/fantasy-land) [](https://gitter.im/fantasyland/fantasy-land?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4 |
5 | (aka "Algebraic JavaScript Specification")
6 |
7 |
8 |
9 | This project specifies interoperability of common algebraic
10 | structures:
11 |
12 |
13 | Setoid Semigroupoid Semigroup Foldable Functor Contravariant Filterable
14 | (equals) (compose) (concat) (reduce) (map) (contramap) (filter)
15 | | | | \ / | | | | \
16 | | | | \ / | | | | \
17 | | | | \ / | | | | \
18 | | | | \ / | | | | \
19 | | | | \ / | | | | \
20 | Ord Category Monoid Traversable | | | | \
21 | (lte) (id) (empty) (traverse) / | | \ \
22 | | / | | \ \
23 | | / / \ \ \
24 | | Profunctor / \ Bifunctor \
25 | | (promap) / \ (bimap) \
26 | | / \ \
27 | Group / \ \
28 | (invert) Alt Apply Extend
29 | (alt) (ap) (extend)
30 | / / \ \
31 | / / \ \
32 | / / \ \
33 | / / \ \
34 | / / \ \
35 | Plus Applicative Chain Comonad
36 | (zero) (of) (chain) (extract)
37 | \ / \ / \
38 | \ / \ / \
39 | \ / \ / \
40 | \ / \ / \
41 | \ / \ / \
42 | Alternative Monad ChainRec
43 | (chainRec)
44 |
45 |
46 | ## General
47 |
48 | An algebra is a set of values, a set of operators that it is closed
49 | under and some laws it must obey.
50 |
51 | Each Fantasy Land algebra is a separate specification. An algebra may
52 | have dependencies on other algebras which must be implemented.
53 |
54 | ## Terminology
55 |
56 | 1. "value" is any JavaScript value, including any which have the
57 | structures defined below.
58 | 2. "equivalent" is an appropriate definition of equivalence for the given value.
59 | The definition should ensure that the two values can be safely swapped out in a program that respects abstractions. For example:
60 | - Two lists are equivalent if they are equivalent at all indices.
61 | - Two plain old JavaScript objects, interpreted as dictionaries, are equivalent when they are equivalent for all keys.
62 | - Two promises are equivalent when they yield equivalent values.
63 | - Two functions are equivalent if they yield equivalent outputs for equivalent inputs.
64 |
65 | ## Type signature notation
66 |
67 | The type signature notation used in this document is described below:[1](#sanctuary-types)
69 |
70 | * `::` _"is a member of"._
71 | - `e :: t` can be read as: "the expression `e` is a member of type `t`".
72 | - `true :: Boolean` - "`true` is a member of type `Boolean`".
73 | - `42 :: Integer, Number` - "`42` is a member of the `Integer` and
74 | `Number` types".
75 | * _New types can be created via type constructors._
76 | - Type constructors can take zero or more type arguments.
77 | - `Array` is a type constructor which takes one type argument.
78 | - `Array String` is the type of all arrays of strings. Each of the
79 | following has type `Array String`: `[]`, `['foo', 'bar', 'baz']`.
80 | - `Array (Array String)` is the type of all arrays of arrays of strings.
81 | Each of the following has type `Array (Array String)`: `[]`, `[ [], []
82 | ]`, `[ [], ['foo'], ['bar', 'baz'] ]`.
83 | * _Lowercase letters stand for type variables._
84 | - Type variables can take any type unless they have been restricted by
85 | means of type constraints (see fat arrow below).
86 | * `->` (arrow) _Function type constructor._
87 | - `->` is an _infix_ type constructor that takes two type arguments where
88 | left argument is the input type and the right argument is the output type.
89 | - `->`'s input type can be a grouping of types to create the type of a
90 | function which accepts zero or more arguments. The syntax is:
91 | `() -> `, where `` comprises zero
92 | or more comma–space (`, `)-separated type representations and parens
93 | may be omitted for unary functions.
94 | - `String -> Array String` is a type satisfied by functions which take a
95 | `String` and return an `Array String`.
96 | - `String -> Array String -> Array String` is a type satisfied by functions
97 | which take a `String` and return a function which takes an `Array String`
98 | and returns an `Array String`.
99 | - `(String, Array String) -> Array String` is a type satisfied by functions
100 | which take a `String` and an `Array String` as arguments and return an
101 | `Array String`.
102 | - `() -> Number` is a type satisfied by functions
103 | which do not take arguments and return a `Number`.
104 | * `~>` (squiggly arrow) _Method type constructor._
105 | - When a function is a property of an Object, it is called a method. All
106 | methods have an implicit parameter type - the type of which they are a
107 | property.
108 | - `a ~> a -> a` is a type satisfied by methods on Objects of type `a` which
109 | take a type `a` as an argument and return a value of type `a`.
110 | * `=>` (fat arrow) _Expresses constraints on type variables._
111 | - In `a ~> a -> a` (see squiggly arrow above), `a` can be of any type.
112 | `Semigroup a => a ~> a -> a` adds a constraint such that the type `a`
113 | must now satisfy the `Semigroup` typeclass. To satisfy a typeclass means
114 | to lawfully implement all functions/methods specified by that typeclass.
115 |
116 | For example:
117 |
118 | ```
119 | fantasy-land/traverse :: Applicative f, Traversable t => t a ~> (TypeRep f, a -> f b) -> f (t b)
120 | '-------------------' '--------------------------' '-' '-------------------' '-----'
121 | ' ' ' ' '
122 | ' ' - type constraints ' ' - argument types ' - return type
123 | ' '
124 | '- method name ' - method target type
125 | ```
126 |
127 | - - -
128 | 1. See the [Types](https://sanctuary.js.org/#types)
129 | section in Sanctuary's docs for more info. [↩](#sanctuary-types-return)
130 |
131 | ## Type representatives
132 |
133 | Certain behaviours are defined from the perspective of a member of a type.
134 | Other behaviours do not require a member. Thus certain algebras require a
135 | type to provide a value-level representative (with certain properties). The
136 | Identity type, for example, could provide `Id` as its type representative:
137 | `Id :: TypeRep Identity`.
138 |
139 | If a type provides a type representative, each member of the type must have
140 | a `constructor` property which is a reference to the type representative.
141 |
142 | ## Algebras
143 |
144 | ### Setoid
145 |
146 | 1. `a['fantasy-land/equals'](a) === true` (reflexivity)
147 | 2. `a['fantasy-land/equals'](b) === b['fantasy-land/equals'](a)` (symmetry)
148 | 3. If `a['fantasy-land/equals'](b)` and `b['fantasy-land/equals'](c)`, then `a['fantasy-land/equals'](c)` (transitivity)
149 |
150 |
151 |
152 | #### `fantasy-land/equals` method
153 |
154 | ```hs
155 | fantasy-land/equals :: Setoid a => a ~> a -> Boolean
156 | ```
157 |
158 | A value which has a Setoid must provide a `fantasy-land/equals` method. The
159 | `fantasy-land/equals` method takes one argument:
160 |
161 | a['fantasy-land/equals'](b)
162 |
163 | 1. `b` must be a value of the same Setoid
164 |
165 | 1. If `b` is not the same Setoid, behaviour of `fantasy-land/equals` is
166 | unspecified (returning `false` is recommended).
167 |
168 | 2. `fantasy-land/equals` must return a boolean (`true` or `false`).
169 |
170 | ### Ord
171 |
172 | A value that implements the Ord specification must also implement
173 | the [Setoid](#setoid) specification.
174 |
175 | 1. `a['fantasy-land/lte'](b)` or `b['fantasy-land/lte'](a)` (totality)
176 | 2. If `a['fantasy-land/lte'](b)` and `b['fantasy-land/lte'](a)`, then `a['fantasy-land/equals'](b)` (antisymmetry)
177 | 3. If `a['fantasy-land/lte'](b)` and `b['fantasy-land/lte'](c)`, then `a['fantasy-land/lte'](c)` (transitivity)
178 |
179 |
180 |
181 | #### `fantasy-land/lte` method
182 |
183 | ```hs
184 | fantasy-land/lte :: Ord a => a ~> a -> Boolean
185 | ```
186 |
187 | A value which has an Ord must provide a `fantasy-land/lte` method. The
188 | `fantasy-land/lte` method takes one argument:
189 |
190 | a['fantasy-land/lte'](b)
191 |
192 | 1. `b` must be a value of the same Ord
193 |
194 | 1. If `b` is not the same Ord, behaviour of `fantasy-land/lte` is
195 | unspecified (returning `false` is recommended).
196 |
197 | 2. `fantasy-land/lte` must return a boolean (`true` or `false`).
198 |
199 | ### Semigroupoid
200 |
201 | 1. `a['fantasy-land/compose'](b)['fantasy-land/compose'](c) === a['fantasy-land/compose'](b['fantasy-land/compose'](c))` (associativity)
202 |
203 |
204 |
205 | #### `fantasy-land/compose` method
206 |
207 | ```hs
208 | fantasy-land/compose :: Semigroupoid c => c i j ~> c j k -> c i k
209 | ```
210 |
211 | A value which has a Semigroupoid must provide a `fantasy-land/compose` method. The
212 | `fantasy-land/compose` method takes one argument:
213 |
214 | a['fantasy-land/compose'](b)
215 |
216 | 1. `b` must be a value of the same Semigroupoid
217 |
218 | 1. If `b` is not the same semigroupoid, behaviour of `fantasy-land/compose` is
219 | unspecified.
220 |
221 | 2. `fantasy-land/compose` must return a value of the same Semigroupoid.
222 |
223 | ### Category
224 |
225 | A value that implements the Category specification must also implement
226 | the [Semigroupoid](#semigroupoid) specification.
227 |
228 | 1. `a['fantasy-land/compose'](C['fantasy-land/id']())` is equivalent to `a` (right identity)
229 | 2. `C['fantasy-land/id']()['fantasy-land/compose'](a)` is equivalent to `a` (left identity)
230 |
231 |
232 |
233 | #### `fantasy-land/id` method
234 |
235 | ```hs
236 | fantasy-land/id :: Category c => () -> c a a
237 | ```
238 |
239 | A value which has a Category must provide a `fantasy-land/id` function on its
240 | [type representative](#type-representatives):
241 |
242 | C['fantasy-land/id']()
243 |
244 | Given a value `c`, one can access its type representative via the
245 | `constructor` property:
246 |
247 | c.constructor['fantasy-land/id']()
248 |
249 | 1. `fantasy-land/id` must return a value of the same Category
250 |
251 | ### Semigroup
252 |
253 | 1. `a['fantasy-land/concat'](b)['fantasy-land/concat'](c)` is equivalent to `a['fantasy-land/concat'](b['fantasy-land/concat'](c))` (associativity)
254 |
255 |
256 |
257 | #### `fantasy-land/concat` method
258 |
259 | ```hs
260 | fantasy-land/concat :: Semigroup a => a ~> a -> a
261 | ```
262 |
263 | A value which has a Semigroup must provide a `fantasy-land/concat` method. The
264 | `fantasy-land/concat` method takes one argument:
265 |
266 | s['fantasy-land/concat'](b)
267 |
268 | 1. `b` must be a value of the same Semigroup
269 |
270 | 1. If `b` is not the same semigroup, behaviour of `fantasy-land/concat` is
271 | unspecified.
272 |
273 | 2. `fantasy-land/concat` must return a value of the same Semigroup.
274 |
275 | ### Monoid
276 |
277 | A value that implements the Monoid specification must also implement
278 | the [Semigroup](#semigroup) specification.
279 |
280 | 1. `m['fantasy-land/concat'](M['fantasy-land/empty']())` is equivalent to `m` (right identity)
281 | 2. `M['fantasy-land/empty']()['fantasy-land/concat'](m)` is equivalent to `m` (left identity)
282 |
283 |
284 |
285 | #### `fantasy-land/empty` method
286 |
287 | ```hs
288 | fantasy-land/empty :: Monoid m => () -> m
289 | ```
290 |
291 | A value which has a Monoid must provide a `fantasy-land/empty` function on its
292 | [type representative](#type-representatives):
293 |
294 | M['fantasy-land/empty']()
295 |
296 | Given a value `m`, one can access its type representative via the
297 | `constructor` property:
298 |
299 | m.constructor['fantasy-land/empty']()
300 |
301 | 1. `fantasy-land/empty` must return a value of the same Monoid
302 |
303 | ### Group
304 |
305 | A value that implements the Group specification must also implement
306 | the [Monoid](#monoid) specification.
307 |
308 | 1. `g['fantasy-land/concat'](g['fantasy-land/invert']())` is equivalent to `g.constructor['fantasy-land/empty']()` (right inverse)
309 | 2. `g['fantasy-land/invert']()['fantasy-land/concat'](g)` is equivalent to `g.constructor['fantasy-land/empty']()` (left inverse)
310 |
311 |
312 |
313 | #### `fantasy-land/invert` method
314 |
315 | ```hs
316 | fantasy-land/invert :: Group g => g ~> () -> g
317 | ```
318 |
319 | A value which has a Group must provide a `fantasy-land/invert` method. The
320 | `fantasy-land/invert` method takes no arguments:
321 |
322 | g['fantasy-land/invert']()
323 |
324 | 1. `fantasy-land/invert` must return a value of the same Group.
325 |
326 | ### Filterable
327 |
328 | 1. `v['fantasy-land/filter'](x => p(x) && q(x))` is equivalent to `v['fantasy-land/filter'](p)['fantasy-land/filter'](q)` (distributivity)
329 | 2. `v['fantasy-land/filter'](x => true)` is equivalent to `v` (identity)
330 | 3. `v['fantasy-land/filter'](x => false)` is equivalent to `w['fantasy-land/filter'](x => false)`
331 | if `v` and `w` are values of the same Filterable (annihilation)
332 |
333 |
334 |
335 | #### `fantasy-land/filter` method
336 |
337 | ```hs
338 | fantasy-land/filter :: Filterable f => f a ~> (a -> Boolean) -> f a
339 | ```
340 |
341 | A value which has a Filterable must provide a `fantasy-land/filter` method. The `fantasy-land/filter`
342 | method takes one argument:
343 |
344 | v['fantasy-land/filter'](p)
345 |
346 | 1. `p` must be a function.
347 |
348 | 1. If `p` is not a function, the behaviour of `fantasy-land/filter` is unspecified.
349 | 2. `p` must return either `true` or `false`. If it returns any other value,
350 | the behaviour of `fantasy-land/filter` is unspecified.
351 |
352 | 2. `fantasy-land/filter` must return a value of the same Filterable.
353 |
354 | ### Functor
355 |
356 | 1. `u['fantasy-land/map'](a => a)` is equivalent to `u` (identity)
357 | 2. `u['fantasy-land/map'](x => f(g(x)))` is equivalent to `u['fantasy-land/map'](g)['fantasy-land/map'](f)` (composition)
358 |
359 |
360 |
361 | #### `fantasy-land/map` method
362 |
363 | ```hs
364 | fantasy-land/map :: Functor f => f a ~> (a -> b) -> f b
365 | ```
366 |
367 | A value which has a Functor must provide a `fantasy-land/map` method. The `fantasy-land/map`
368 | method takes one argument:
369 |
370 | u['fantasy-land/map'](f)
371 |
372 | 1. `f` must be a function,
373 |
374 | 1. If `f` is not a function, the behaviour of `fantasy-land/map` is
375 | unspecified.
376 | 2. `f` can return any value.
377 | 3. No parts of `f`'s return value should be checked.
378 |
379 | 2. `fantasy-land/map` must return a value of the same Functor
380 |
381 | ### Contravariant
382 |
383 | 1. `u['fantasy-land/contramap'](a => a)` is equivalent to `u` (identity)
384 | 2. `u['fantasy-land/contramap'](x => f(g(x)))` is equivalent to `u['fantasy-land/contramap'](f)['fantasy-land/contramap'](g)`
385 | (composition)
386 |
387 |
388 |
389 | #### `fantasy-land/contramap` method
390 |
391 | ```hs
392 | fantasy-land/contramap :: Contravariant f => f a ~> (b -> a) -> f b
393 | ```
394 |
395 | A value which has a Contravariant must provide a `fantasy-land/contramap` method. The
396 | `fantasy-land/contramap` method takes one argument:
397 |
398 | u['fantasy-land/contramap'](f)
399 |
400 | 1. `f` must be a function,
401 |
402 | 1. If `f` is not a function, the behaviour of `fantasy-land/contramap` is
403 | unspecified.
404 | 2. `f` can return any value.
405 | 3. No parts of `f`'s return value should be checked.
406 |
407 | 2. `fantasy-land/contramap` must return a value of the same Contravariant
408 |
409 | ### Apply
410 |
411 | A value that implements the Apply specification must also
412 | implement the [Functor](#functor) specification.
413 |
414 | 1. `v['fantasy-land/ap'](u['fantasy-land/ap'](a['fantasy-land/map'](f => g => x => f(g(x)))))` is equivalent to `v['fantasy-land/ap'](u)['fantasy-land/ap'](a)` (composition)
415 |
416 |
417 |
418 | #### `fantasy-land/ap` method
419 |
420 | ```hs
421 | fantasy-land/ap :: Apply f => f a ~> f (a -> b) -> f b
422 | ```
423 |
424 | A value which has an Apply must provide a `fantasy-land/ap` method. The `fantasy-land/ap`
425 | method takes one argument:
426 |
427 | a['fantasy-land/ap'](b)
428 |
429 | 1. `b` must be an Apply of a function
430 |
431 | 1. If `b` does not represent a function, the behaviour of `fantasy-land/ap` is
432 | unspecified.
433 | 2. `b` must be same Apply as `a`.
434 |
435 | 2. `a` must be an Apply of any value
436 |
437 | 3. `fantasy-land/ap` must apply the function in Apply `b` to the value in
438 | Apply `a`
439 |
440 | 1. No parts of return value of that function should be checked.
441 |
442 | 4. The `Apply` returned by `fantasy-land/ap` must be the same as `a` and `b`
443 |
444 | ### Applicative
445 |
446 | A value that implements the Applicative specification must also
447 | implement the [Apply](#apply) specification.
448 |
449 | 1. `v['fantasy-land/ap'](A['fantasy-land/of'](x => x))` is equivalent to `v` (identity)
450 | 2. `A['fantasy-land/of'](x)['fantasy-land/ap'](A['fantasy-land/of'](f))` is equivalent to `A['fantasy-land/of'](f(x))` (homomorphism)
451 | 3. `A['fantasy-land/of'](y)['fantasy-land/ap'](u)` is equivalent to `u['fantasy-land/ap'](A['fantasy-land/of'](f => f(y)))` (interchange)
452 |
453 |
454 |
455 | #### `fantasy-land/of` method
456 |
457 | ```hs
458 | fantasy-land/of :: Applicative f => a -> f a
459 | ```
460 |
461 | A value which has an Applicative must provide a `fantasy-land/of` function on its
462 | [type representative](#type-representatives). The `fantasy-land/of` function takes
463 | one argument:
464 |
465 | F['fantasy-land/of'](a)
466 |
467 | Given a value `f`, one can access its type representative via the
468 | `constructor` property:
469 |
470 | f.constructor['fantasy-land/of'](a)
471 |
472 | 1. `fantasy-land/of` must provide a value of the same Applicative
473 |
474 | 1. No parts of `a` should be checked
475 |
476 | ### Alt
477 |
478 | A value that implements the Alt specification must also implement
479 | the [Functor](#functor) specification.
480 |
481 | 1. `a['fantasy-land/alt'](b)['fantasy-land/alt'](c)` is equivalent to `a['fantasy-land/alt'](b['fantasy-land/alt'](c))` (associativity)
482 | 2. `a['fantasy-land/alt'](b)['fantasy-land/map'](f)` is equivalent to `a['fantasy-land/map'](f)['fantasy-land/alt'](b['fantasy-land/map'](f))` (distributivity)
483 |
484 |
485 |
486 | #### `fantasy-land/alt` method
487 |
488 | ```hs
489 | fantasy-land/alt :: Alt f => f a ~> f a -> f a
490 | ```
491 |
492 | A value which has a Alt must provide a `fantasy-land/alt` method. The
493 | `fantasy-land/alt` method takes one argument:
494 |
495 | a['fantasy-land/alt'](b)
496 |
497 | 1. `b` must be a value of the same Alt
498 |
499 | 1. If `b` is not the same Alt, behaviour of `fantasy-land/alt` is
500 | unspecified.
501 | 2. `a` and `b` can contain any value of same type.
502 | 3. No parts of `a`'s and `b`'s containing value should be checked.
503 |
504 | 2. `fantasy-land/alt` must return a value of the same Alt.
505 |
506 | ### Plus
507 |
508 | A value that implements the Plus specification must also implement
509 | the [Alt](#alt) specification.
510 |
511 | 1. `x['fantasy-land/alt'](A['fantasy-land/zero']())` is equivalent to `x` (right identity)
512 | 2. `A['fantasy-land/zero']()['fantasy-land/alt'](x)` is equivalent to `x` (left identity)
513 | 3. `A['fantasy-land/zero']()['fantasy-land/map'](f)` is equivalent to `A['fantasy-land/zero']()` (annihilation)
514 |
515 |
516 |
517 | #### `fantasy-land/zero` method
518 |
519 | ```hs
520 | fantasy-land/zero :: Plus f => () -> f a
521 | ```
522 |
523 | A value which has a Plus must provide a `fantasy-land/zero` function on its
524 | [type representative](#type-representatives):
525 |
526 | A['fantasy-land/zero']()
527 |
528 | Given a value `x`, one can access its type representative via the
529 | `constructor` property:
530 |
531 | x.constructor['fantasy-land/zero']()
532 |
533 | 1. `fantasy-land/zero` must return a value of the same Plus
534 |
535 | ### Alternative
536 |
537 | A value that implements the Alternative specification must also implement
538 | the [Applicative](#applicative) and [Plus](#plus) specifications.
539 |
540 | 1. `x['fantasy-land/ap'](f['fantasy-land/alt'](g))` is equivalent to `x['fantasy-land/ap'](f)['fantasy-land/alt'](x['fantasy-land/ap'](g))` (distributivity)
541 | 2. `x['fantasy-land/ap'](A['fantasy-land/zero']())` is equivalent to `A['fantasy-land/zero']()` (annihilation)
542 |
543 | ### Foldable
544 |
545 | 1. `u['fantasy-land/reduce']` is equivalent to `u['fantasy-land/reduce']((acc, x) => acc.concat([x]), []).reduce`
546 |
547 |
548 |
549 | #### `fantasy-land/reduce` method
550 |
551 | ```hs
552 | fantasy-land/reduce :: Foldable f => f a ~> ((b, a) -> b, b) -> b
553 | ```
554 |
555 | A value which has a Foldable must provide a `fantasy-land/reduce` method. The `fantasy-land/reduce`
556 | method takes two arguments:
557 |
558 | u['fantasy-land/reduce'](f, x)
559 |
560 | 1. `f` must be a binary function
561 |
562 | 1. if `f` is not a function, the behaviour of `fantasy-land/reduce` is unspecified.
563 | 2. The first argument to `f` must be the same type as `x`.
564 | 3. `f` must return a value of the same type as `x`.
565 | 4. No parts of `f`'s return value should be checked.
566 |
567 | 1. `x` is the initial accumulator value for the reduction
568 |
569 | 1. No parts of `x` should be checked.
570 |
571 | ### Traversable
572 |
573 | A value that implements the Traversable specification must also
574 | implement the [Functor](#functor) and [Foldable](#foldable) specifications.
575 |
576 | 1. `t(u['fantasy-land/traverse'](F, x => x))` is equivalent to `u['fantasy-land/traverse'](G, t)` for any
577 | `t` such that `t(a)['fantasy-land/map'](f)` is equivalent to `t(a['fantasy-land/map'](f))` (naturality)
578 |
579 | 2. `u['fantasy-land/traverse'](F, F['fantasy-land/of'])` is equivalent to `F['fantasy-land/of'](u)` for any Applicative `F`
580 | (identity)
581 |
582 | 3. `u['fantasy-land/traverse'](Compose, x => new Compose(x))` is equivalent to
583 | `new Compose(u['fantasy-land/traverse'](F, x => x)['fantasy-land/map'](x => x['fantasy-land/traverse'](G, x => x)))` for
584 | `Compose` defined below and any Applicatives `F` and `G` (composition)
585 |
586 | ```js
587 | function Compose(c) {
588 | this.c = c;
589 | }
590 |
591 | Compose['fantasy-land/of'] = function(x) {
592 | return new Compose(F['fantasy-land/of'](G['fantasy-land/of'](x)));
593 | };
594 |
595 | Compose.prototype['fantasy-land/ap'] = function(f) {
596 | return new Compose(this.c['fantasy-land/ap'](f.c['fantasy-land/map'](u => y => y['fantasy-land/ap'](u))));
597 | };
598 |
599 | Compose.prototype['fantasy-land/map'] = function(f) {
600 | return new Compose(this.c['fantasy-land/map'](y => y['fantasy-land/map'](f)));
601 | };
602 | ```
603 |
604 |
605 |
606 | #### `fantasy-land/traverse` method
607 |
608 | ```hs
609 | fantasy-land/traverse :: Applicative f, Traversable t => t a ~> (TypeRep f, a -> f b) -> f (t b)
610 | ```
611 |
612 | A value which has a Traversable must provide a `fantasy-land/traverse` method. The `fantasy-land/traverse`
613 | method takes two arguments:
614 |
615 | u['fantasy-land/traverse'](A, f)
616 |
617 | 1. `A` must be the [type representative](#type-representatives) of an
618 | Applicative.
619 |
620 | 2. `f` must be a function which returns a value
621 |
622 | 1. If `f` is not a function, the behaviour of `fantasy-land/traverse` is
623 | unspecified.
624 | 2. `f` must return a value of the type represented by `A`.
625 |
626 | 3. `fantasy-land/traverse` must return a value of the type represented by `A`.
627 |
628 | ### Chain
629 |
630 | A value that implements the Chain specification must also
631 | implement the [Apply](#apply) specification.
632 |
633 | 1. `m['fantasy-land/chain'](f)['fantasy-land/chain'](g)` is equivalent to `m['fantasy-land/chain'](x => f(x)['fantasy-land/chain'](g))` (associativity)
634 |
635 |
636 |
637 | #### `fantasy-land/chain` method
638 |
639 | ```hs
640 | fantasy-land/chain :: Chain m => m a ~> (a -> m b) -> m b
641 | ```
642 |
643 | A value which has a Chain must provide a `fantasy-land/chain` method. The `fantasy-land/chain`
644 | method takes one argument:
645 |
646 | m['fantasy-land/chain'](f)
647 |
648 | 1. `f` must be a function which returns a value
649 |
650 | 1. If `f` is not a function, the behaviour of `fantasy-land/chain` is
651 | unspecified.
652 | 2. `f` must return a value of the same Chain
653 |
654 | 2. `fantasy-land/chain` must return a value of the same Chain
655 |
656 | ### ChainRec
657 |
658 | A value that implements the ChainRec specification must also implement the [Chain](#chain) specification.
659 |
660 | 1. `M['fantasy-land/chainRec']((next, done, v) => p(v) ? d(v)['fantasy-land/map'](done) : n(v)['fantasy-land/map'](next), i)`
661 | is equivalent to
662 | `(function step(v) { return p(v) ? d(v) : n(v)['fantasy-land/chain'](step); }(i))` (equivalence)
663 | 2. Stack usage of `M['fantasy-land/chainRec'](f, i)` must be at most a constant multiple of the stack usage of `f` itself.
664 |
665 |
666 |
667 | #### `fantasy-land/chainRec` method
668 |
669 | ```hs
670 | fantasy-land/chainRec :: ChainRec m => ((a -> c, b -> c, a) -> m c, a) -> m b
671 | ```
672 |
673 | A Type which has a ChainRec must provide a `fantasy-land/chainRec` function on its
674 | [type representative](#type-representatives). The `fantasy-land/chainRec` function
675 | takes two arguments:
676 |
677 | M['fantasy-land/chainRec'](f, i)
678 |
679 | Given a value `m`, one can access its type representative via the
680 | `constructor` property:
681 |
682 | m.constructor['fantasy-land/chainRec'](f, i)
683 |
684 | 1. `f` must be a function which returns a value
685 | 1. If `f` is not a function, the behaviour of `fantasy-land/chainRec` is unspecified.
686 | 2. `f` takes three arguments `next`, `done`, `value`
687 | 1. `next` is a function which takes one argument of same type as `i` and can return any value
688 | 2. `done` is a function which takes one argument and returns the same type as the return value of `next`
689 | 3. `value` is some value of the same type as `i`
690 | 3. `f` must return a value of the same ChainRec which contains a value returned from either `done` or `next`
691 | 2. `fantasy-land/chainRec` must return a value of the same ChainRec which contains a value of same type as argument of `done`
692 |
693 | ### Monad
694 |
695 | A value that implements the Monad specification must also implement
696 | the [Applicative](#applicative) and [Chain](#chain) specifications.
697 |
698 | 1. `M['fantasy-land/of'](a)['fantasy-land/chain'](f)` is equivalent to `f(a)` (left identity)
699 | 2. `m['fantasy-land/chain'](M['fantasy-land/of'])` is equivalent to `m` (right identity)
700 |
701 | ### Extend
702 |
703 | A value that implements the Extend specification must also implement the [Functor](#functor) specification.
704 |
705 | 1. `w['fantasy-land/extend'](g)['fantasy-land/extend'](f)` is equivalent to `w['fantasy-land/extend'](_w => f(_w['fantasy-land/extend'](g)))`
706 |
707 |
708 |
709 | #### `fantasy-land/extend` method
710 |
711 | ```hs
712 | fantasy-land/extend :: Extend w => w a ~> (w a -> b) -> w b
713 | ```
714 |
715 | An Extend must provide a `fantasy-land/extend` method. The `fantasy-land/extend`
716 | method takes one argument:
717 |
718 | w['fantasy-land/extend'](f)
719 |
720 | 1. `f` must be a function which returns a value
721 |
722 | 1. If `f` is not a function, the behaviour of `fantasy-land/extend` is
723 | unspecified.
724 | 2. `f` must return a value of type `v`, for some variable `v` contained in `w`.
725 | 3. No parts of `f`'s return value should be checked.
726 |
727 | 2. `fantasy-land/extend` must return a value of the same Extend.
728 |
729 | ### Comonad
730 |
731 | A value that implements the Comonad specification must also implement the [Extend](#extend) specification.
732 |
733 | 1. `w['fantasy-land/extend'](_w => _w['fantasy-land/extract']())` is equivalent to `w` (left identity)
734 | 2. `w['fantasy-land/extend'](f)['fantasy-land/extract']()` is equivalent to `f(w)` (right identity)
735 |
736 |
737 |
738 | #### `fantasy-land/extract` method
739 |
740 | ```hs
741 | fantasy-land/extract :: Comonad w => w a ~> () -> a
742 | ```
743 |
744 | A value which has a Comonad must provide a `fantasy-land/extract` method on itself.
745 | The `fantasy-land/extract` method takes no arguments:
746 |
747 | w['fantasy-land/extract']()
748 |
749 | 1. `fantasy-land/extract` must return a value of type `v`, for some variable `v` contained in `w`.
750 | 1. `v` must have the same type that `f` returns in `fantasy-land/extend`.
751 |
752 | ### Bifunctor
753 |
754 | A value that implements the Bifunctor specification must also implement
755 | the [Functor](#functor) specification.
756 |
757 | 1. `p['fantasy-land/bimap'](a => a, b => b)` is equivalent to `p` (identity)
758 | 2. `p['fantasy-land/bimap'](a => f(g(a)), b => h(i(b)))` is equivalent to `p['fantasy-land/bimap'](g, i)['fantasy-land/bimap'](f, h)` (composition)
759 |
760 |
761 |
762 | #### `fantasy-land/bimap` method
763 |
764 | ```hs
765 | fantasy-land/bimap :: Bifunctor f => f a c ~> (a -> b, c -> d) -> f b d
766 | ```
767 |
768 | A value which has a Bifunctor must provide a `fantasy-land/bimap` method. The `fantasy-land/bimap`
769 | method takes two arguments:
770 |
771 | c['fantasy-land/bimap'](f, g)
772 |
773 | 1. `f` must be a function which returns a value
774 |
775 | 1. If `f` is not a function, the behaviour of `fantasy-land/bimap` is unspecified.
776 | 2. `f` can return any value.
777 | 3. No parts of `f`'s return value should be checked.
778 |
779 | 2. `g` must be a function which returns a value
780 |
781 | 1. If `g` is not a function, the behaviour of `fantasy-land/bimap` is unspecified.
782 | 2. `g` can return any value.
783 | 3. No parts of `g`'s return value should be checked.
784 |
785 | 3. `fantasy-land/bimap` must return a value of the same Bifunctor.
786 |
787 | ### Profunctor
788 |
789 | A value that implements the Profunctor specification must also implement
790 | the [Functor](#functor) specification.
791 |
792 | 1. `p['fantasy-land/promap'](a => a, b => b)` is equivalent to `p` (identity)
793 | 2. `p['fantasy-land/promap'](a => f(g(a)), b => h(i(b)))` is equivalent to `p['fantasy-land/promap'](f, i)['fantasy-land/promap'](g, h)` (composition)
794 |
795 |
796 |
797 | #### `fantasy-land/promap` method
798 |
799 | ```hs
800 | fantasy-land/promap :: Profunctor p => p b c ~> (a -> b, c -> d) -> p a d
801 | ```
802 |
803 | A value which has a Profunctor must provide a `fantasy-land/promap` method.
804 |
805 | The `fantasy-land/promap` method takes two arguments:
806 |
807 | c['fantasy-land/promap'](f, g)
808 |
809 | 1. `f` must be a function which returns a value
810 |
811 | 1. If `f` is not a function, the behaviour of `fantasy-land/promap` is unspecified.
812 | 2. `f` can return any value.
813 | 3. No parts of `f`'s return value should be checked.
814 |
815 | 2. `g` must be a function which returns a value
816 |
817 | 1. If `g` is not a function, the behaviour of `fantasy-land/promap` is unspecified.
818 | 2. `g` can return any value.
819 | 3. No parts of `g`'s return value should be checked.
820 |
821 | 3. `fantasy-land/promap` must return a value of the same Profunctor
822 |
823 | ## Derivations
824 |
825 | When creating data types which satisfy multiple algebras, authors may choose
826 | to implement certain methods then derive the remaining methods. Derivations:
827 |
828 | - [`fantasy-land/equals`][] may be derived from [`fantasy-land/lte`][]:
829 |
830 | ```js
831 | function equals(other) { return this['fantasy-land/lte'](other) && other['fantasy-land/lte'](this); }
832 | ```
833 |
834 | - [`fantasy-land/map`][] may be derived from [`fantasy-land/ap`][] and [`fantasy-land/of`][]:
835 |
836 | ```js
837 | function map(f) { return this['fantasy-land/ap'](this.constructor['fantasy-land/of'](f)); }
838 | ```
839 |
840 | - [`fantasy-land/map`][] may be derived from [`fantasy-land/chain`][] and [`fantasy-land/of`][]:
841 |
842 | ```js
843 | function map(f) { return this['fantasy-land/chain'](a => this.constructor['fantasy-land/of'](f(a))); }
844 | ```
845 |
846 | - [`fantasy-land/map`][] may be derived from [`fantasy-land/bimap`][]:
847 |
848 | ```js
849 | function map(f) { return this['fantasy-land/bimap'](a => a, f); }
850 | ```
851 |
852 | - [`fantasy-land/map`][] may be derived from [`fantasy-land/promap`][]:
853 |
854 | ```js
855 | function map(f) { return this['fantasy-land/promap'](a => a, f); }
856 | ```
857 |
858 | - [`fantasy-land/ap`][] may be derived from [`fantasy-land/chain`][]:
859 |
860 | ```js
861 | function ap(m) { return m['fantasy-land/chain'](f => this['fantasy-land/map'](f)); }
862 | ```
863 |
864 | - [`fantasy-land/reduce`][] may be derived as follows:
865 |
866 | ```js
867 | function reduce(f, acc) {
868 | function Const(value) {
869 | this.value = value;
870 | }
871 | Const['fantasy-land/of'] = function(_) {
872 | return new Const(acc);
873 | };
874 | Const.prototype['fantasy-land/map'] = function(_) {
875 | return this;
876 | };
877 | Const.prototype['fantasy-land/ap'] = function(b) {
878 | return new Const(f(b.value, this.value));
879 | };
880 | return this['fantasy-land/traverse'](x => new Const(x), Const['fantasy-land/of']).value;
881 | }
882 | ```
883 |
884 | - [`fantasy-land/map`][] may be derived as follows:
885 |
886 | ```js
887 | function map(f) {
888 | function Id(value) {
889 | this.value = value;
890 | }
891 | Id['fantasy-land/of'] = function(x) {
892 | return new Id(x);
893 | };
894 | Id.prototype['fantasy-land/map'] = function(f) {
895 | return new Id(f(this.value));
896 | };
897 | Id.prototype['fantasy-land/ap'] = function(b) {
898 | return new Id(this.value(b.value));
899 | };
900 | return this['fantasy-land/traverse'](x => Id['fantasy-land/of'](f(x)), Id['fantasy-land/of']).value;
901 | }
902 | ```
903 |
904 | - [`fantasy-land/filter`][] may be derived from [`fantasy-land/of`][], [`fantasy-land/chain`][], and [`fantasy-land/zero`][]:
905 |
906 | ```js
907 | function filter(pred) {
908 | var F = this.constructor;
909 | return this['fantasy-land/chain'](x => pred(x) ? F['fantasy-land/of'](x) : F['fantasy-land/zero']());
910 | }
911 | ```
912 |
913 | - [`fantasy-land/filter`][] may be derived from [`fantasy-land/concat`][], [`fantasy-land/of`][], [`fantasy-land/zero`][], and
914 | [`fantasy-land/reduce`][]:
915 |
916 | ```js
917 | function filter(pred) {
918 | var F = this.constructor;
919 | return this['fantasy-land/reduce']((f, x) => pred(x) ? f['fantasy-land/concat'](F['fantasy-land/of'](x)) : f, F['fantasy-land/zero']());
920 | }
921 | ```
922 |
923 | If a data type provides a method which *could* be derived, its behaviour must
924 | be equivalent to that of the derivation (or derivations).
925 |
926 | ## Notes
927 |
928 | 1. If there's more than a single way to implement the methods and
929 | laws, the implementation should choose one and provide wrappers for
930 | other uses.
931 | 2. It's discouraged to overload the specified methods. It can easily
932 | result in broken and buggy behaviour.
933 | 3. It is recommended to throw an exception on unspecified behaviour.
934 | 4. An `Identity` container which implements many of the methods is provided by
935 | [sanctuary-identity](https://github.com/sanctuary-js/sanctuary-identity).
936 |
937 |
938 | [`fantasy-land/ap`]: #ap-method
939 | [`fantasy-land/bimap`]: #bimap-method
940 | [`fantasy-land/chain`]: #chain-method
941 | [`fantasy-land/concat`]: #concat-method
942 | [`fantasy-land/equals`]: #equals-method
943 | [`fantasy-land/filter`]: #filter-method
944 | [`fantasy-land/lte`]: #lte-method
945 | [`fantasy-land/map`]: #map-method
946 | [`fantasy-land/of`]: #of-method
947 | [`fantasy-land/promap`]: #promap-method
948 | [`fantasy-land/reduce`]: #reduce-method
949 | [`fantasy-land/zero`]: #zero-method
950 |
951 | ## Alternatives
952 |
953 | There also exists [Static Land Specification](https://github.com/rpominov/static-land)
954 | with exactly the same ideas as Fantasy Land but based on static methods instead of instance methods.
955 |
--------------------------------------------------------------------------------
/figures/dependencies.dot:
--------------------------------------------------------------------------------
1 | digraph {
2 | node [shape=plaintext]
3 |
4 | # Algebras
5 | Alt;
6 | Alternative;
7 | Applicative;
8 | Apply;
9 | Bifunctor;
10 | Category;
11 | Chain;
12 | ChainRec;
13 | Comonad;
14 | Contravariant;
15 | Extend;
16 | Filterable;
17 | Foldable;
18 | Functor;
19 | Group;
20 | Monad;
21 | Monoid;
22 | Ord;
23 | Plus;
24 | Profunctor;
25 | Semigroup;
26 | Semigroupoid;
27 | Setoid;
28 | Traversable;
29 |
30 | # Dependencies
31 | Alt -> Plus;
32 | Applicative -> Alternative;
33 | Applicative -> Monad;
34 | Apply -> Applicative;
35 | Apply -> Chain;
36 | Chain -> ChainRec;
37 | Chain -> Monad;
38 | Extend -> Comonad;
39 | Foldable -> Traversable;
40 | Functor -> Alt;
41 | Functor -> Apply;
42 | Functor -> Bifunctor;
43 | Functor -> Extend;
44 | Functor -> Profunctor;
45 | Functor -> Traversable;
46 | Monoid -> Group;
47 | Plus -> Alternative;
48 | Semigroup -> Monoid;
49 | Semigroupoid -> Category;
50 | Setoid -> Ord;
51 | }
52 |
--------------------------------------------------------------------------------
/figures/dependencies.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | dot -Tpng -odependencies.png dependencies.dot
4 |
--------------------------------------------------------------------------------
/implementations.md:
--------------------------------------------------------------------------------
1 | # Conformant Implementations
2 |
3 | Here are a list of implementations that live in Fantasy Land:
4 |
5 | * [Most.js](https://github.com/cujojs/most) implements Monoid, Functor, Applicative, and Monad for streams
6 | * [creed](https://github.com/briancavalier/creed) implements Monoid, Functor, Applicative, and Monad for promises, and interops with Promises/A+ and ES2015 Promise
7 | * [bacon.js](https://github.com/raimohanska/bacon.js) implements
8 | Monad and Functor for EventStream and Property on the "fantasy-land" branch
9 | * [aljebra](https://github.com/markandrus/aljebra) implements common
10 | Monoid structures from Haskell
11 | * [supervis.es](https://github.com/raganwald/supervis.es) contains many
12 | structures that implement Monad
13 | * [sweet-fantasies](https://github.com/pufuwozu/sweet-fantasies) provides
14 | macros for syntactic sugar of Semigroup and Monad
15 | * [Fantasy Promises](https://github.com/pufuwozu/fantasy-promises)
16 | implements Monad and Functor for Promise
17 | * [Fantasy Sorcery](https://github.com/pufuwozu/fantasy-sorcery)
18 | provides common functions that work for Fantasy Land structures
19 | * ECMAScript 5 provides a Semigroup, Functor, and Foldable for Array
20 | * [lz](https://github.com/goatslacker/lz) implements Semigroup, Monoid, Functor, and Monad for lazy Array and String
21 | * [Pacta](https://github.com/mudge/pacta) is an algebraic implementation of
22 | Promises that implements Semigroup, Monoid, Functor, Applicative, Chain and
23 | Monad
24 | * [Pirandello](https://github.com/quarterto/Pirandello) better streams, with a MonadPlus
25 | * [Parsimmon](https://github.com/jayferd/parsimmon) implements parsers that are semigroups, applicative functors, and monads.
26 | * [Bennu](https://github.com/mattbierner/bennu/) parsec style parser combinators implement monad, monoid, functor, and applicative functor.
27 | * [Akh](https://github.com/mattbierner/akh/) is a collection of monad transformers and common structures that implement Fantasy Land interfaces.
28 | * [TsMonad](https://github.com/cbowdon/tsmonad) implements some common monads for TypeScript.
29 | * [List in JS](https://github.com/PandaNoir/List-in-JS/) implements Setoid, Semigroup, Monoid, Functor, Applicative, Foldable, Traversable, Chain and Monad.
30 | * [Sanctuary](https://github.com/plaid/sanctuary) is a refuge from unsafe JavaScript. It provides FL-compatible Either and Maybe types.
31 | * [Fluture](https://github.com/Avaq/Fluture) is a high-performance monadic alternative to Promises.
32 | * [Ramda Adjunct](https://github.com/char0n/ramda-adjunct) is a community-maintained extension of Ramda
33 | * [Folktale](https://folktale.origamitower.com/) implements Maybe, Result, Validation, Task and Future as FL-compatible types.
34 | * [Monastic](https://github.com/wearereasonablepeople/monastic) implements a Fantasy Land 3 compliant State Monad.
35 | * [SodiumFRP](https://github.com/sodiumFRP/sodium-typescript) implements Functor and Monoid for Streams, as well as Monad and Comonad for Cells.
36 | * [Zion](https://github.com/osstotalsoft/jsbb/tree/master/packages/zion) provides FL-compatible types like Maybe, List, Map, Reader, Step and polymorphic fns.
37 | * [purify](https://github.com/gigobyte/purify/) contains structures that implement Functor, Monad, and a lot of other Fantasy Land interfaces.
38 |
39 | Conforming implementations are encouraged to promote the Fantasy Land logo:
40 |
41 | 
42 |
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | export const equals: 'fantasy-land/equals';
2 | export const lte: 'fantasy-land/lte';
3 | export const compose: 'fantasy-land/compose';
4 | export const id: 'fantasy-land/id';
5 | export const concat: 'fantasy-land/concat';
6 | export const empty: 'fantasy-land/empty';
7 | export const invert: 'fantasy-land/invert';
8 | export const filter: 'fantasy-land/filter';
9 | export const map: 'fantasy-land/map';
10 | export const contramap: 'fantasy-land/contramap';
11 | export const ap: 'fantasy-land/ap';
12 | export const of: 'fantasy-land/of';
13 | export const alt: 'fantasy-land/alt';
14 | export const zero: 'fantasy-land/zero';
15 | export const reduce: 'fantasy-land/reduce';
16 | export const traverse: 'fantasy-land/traverse';
17 | export const chain: 'fantasy-land/chain';
18 | export const chainRec: 'fantasy-land/chainRec';
19 | export const extend: 'fantasy-land/extend';
20 | export const extract: 'fantasy-land/extract';
21 | export const bimap: 'fantasy-land/bimap';
22 | export const promap: 'fantasy-land/promap';
23 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | 'use strict';
4 |
5 | var mapping = {
6 | equals: 'fantasy-land/equals',
7 | lte: 'fantasy-land/lte',
8 | compose: 'fantasy-land/compose',
9 | id: 'fantasy-land/id',
10 | concat: 'fantasy-land/concat',
11 | empty: 'fantasy-land/empty',
12 | invert: 'fantasy-land/invert',
13 | filter: 'fantasy-land/filter',
14 | map: 'fantasy-land/map',
15 | contramap: 'fantasy-land/contramap',
16 | ap: 'fantasy-land/ap',
17 | of: 'fantasy-land/of',
18 | alt: 'fantasy-land/alt',
19 | zero: 'fantasy-land/zero',
20 | reduce: 'fantasy-land/reduce',
21 | traverse: 'fantasy-land/traverse',
22 | chain: 'fantasy-land/chain',
23 | chainRec: 'fantasy-land/chainRec',
24 | extend: 'fantasy-land/extend',
25 | extract: 'fantasy-land/extract',
26 | bimap: 'fantasy-land/bimap',
27 | promap: 'fantasy-land/promap'
28 | };
29 |
30 | /* istanbul ignore else */
31 | if (typeof module === 'object' && typeof module.exports === 'object') {
32 | module.exports = mapping;
33 | } else {
34 | self.FantasyLand = mapping;
35 | }
36 |
37 | } ());
38 |
--------------------------------------------------------------------------------
/index.mjs:
--------------------------------------------------------------------------------
1 | export const equals = 'fantasy-land/equals';
2 | export const lte = 'fantasy-land/lte';
3 | export const compose = 'fantasy-land/compose';
4 | export const id = 'fantasy-land/id';
5 | export const concat = 'fantasy-land/concat';
6 | export const empty = 'fantasy-land/empty';
7 | export const invert = 'fantasy-land/invert';
8 | export const filter = 'fantasy-land/filter';
9 | export const map = 'fantasy-land/map';
10 | export const contramap = 'fantasy-land/contramap';
11 | export const ap = 'fantasy-land/ap';
12 | export const of = 'fantasy-land/of';
13 | export const alt = 'fantasy-land/alt';
14 | export const zero = 'fantasy-land/zero';
15 | export const reduce = 'fantasy-land/reduce';
16 | export const traverse = 'fantasy-land/traverse';
17 | export const chain = 'fantasy-land/chain';
18 | export const chainRec = 'fantasy-land/chainRec';
19 | export const extend = 'fantasy-land/extend';
20 | export const extract = 'fantasy-land/extract';
21 | export const bimap = 'fantasy-land/bimap';
22 | export const promap = 'fantasy-land/promap';
23 |
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fantasyland/fantasy-land/0fc5ba5b3699046b024d21fe023c8bfef8d482d0/logo.png
--------------------------------------------------------------------------------
/names:
--------------------------------------------------------------------------------
1 | equals
2 | lte
3 | compose
4 | id
5 | concat
6 | empty
7 | invert
8 | filter
9 | map
10 | contramap
11 | ap
12 | of
13 | alt
14 | zero
15 | reduce
16 | traverse
17 | chain
18 | chainRec
19 | extend
20 | extract
21 | bimap
22 | promap
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fantasy-land",
3 | "author": "Brian McKenna",
4 | "version": "5.0.1",
5 | "description": "Specification for interoperability of common algebraic structures in JavaScript",
6 | "license": "MIT",
7 | "homepage": "https://github.com/fantasyland/fantasy-land",
8 | "keywords": [
9 | "algebraic",
10 | "monad",
11 | "applicative",
12 | "functor",
13 | "monoid",
14 | "semigroup",
15 | "chain",
16 | "apply"
17 | ],
18 | "issues": {
19 | "url": "https://github.com/fantasyland/fantasy-land/issues"
20 | },
21 | "dependencies": {},
22 | "devDependencies": {
23 | "sanctuary-scripts": "2.x.x"
24 | },
25 | "repository": {
26 | "type": "git",
27 | "url": "git://github.com/fantasyland/fantasy-land.git"
28 | },
29 | "files": [
30 | "/LICENSE",
31 | "/README.md",
32 | "/index.d.ts",
33 | "/index.js",
34 | "/index.mjs",
35 | "/package.json"
36 | ],
37 | "main": "index.js",
38 | "exports": {
39 | "types": "./index.d.ts",
40 | "require": "./index.js",
41 | "import": "./index.mjs"
42 | },
43 | "scripts": {
44 | "doctest": "sanctuary-doctest",
45 | "generate-es": "scripts/generate-es",
46 | "generate-js": "scripts/generate-js",
47 | "generate-ts": "scripts/generate-ts",
48 | "lint": "sanctuary-lint",
49 | "release": "sanctuary-release",
50 | "test": "npm run lint && sanctuary-test && npm run doctest"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/scripts/generate-es:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -euf -o pipefail
3 |
4 | awk '{ print "export const " $0 " = \047fantasy-land/" $0 "\047;" }' names >index.mjs
5 |
--------------------------------------------------------------------------------
/scripts/generate-js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -euf -o pipefail
3 |
4 | cat >index.js < 1 ? ",\n " : "") $0 ": \047fantasy-land/" $0 "\047" }' names)
11 | };
12 |
13 | /* istanbul ignore else */
14 | if (typeof module === 'object' && typeof module.exports === 'object') {
15 | module.exports = mapping;
16 | } else {
17 | self.FantasyLand = mapping;
18 | }
19 |
20 | } ());
21 | EOF
22 |
--------------------------------------------------------------------------------
/scripts/generate-readme:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fantasyland/fantasy-land/0fc5ba5b3699046b024d21fe023c8bfef8d482d0/scripts/generate-readme
--------------------------------------------------------------------------------
/scripts/generate-ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -euf -o pipefail
3 |
4 | awk '{ print "export const " $0 ": \047fantasy-land/" $0 "\047;" }' names >index.d.ts
5 |
--------------------------------------------------------------------------------
/scripts/lint:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -euf -o pipefail
3 |
4 | node_modules/.bin/sanctuary-lint "$@"
5 |
6 | scripts/generate-js && git diff --exit-code index.js
7 | scripts/generate-ts && git diff --exit-code index.d.ts
8 | scripts/generate-es && git diff --exit-code index.mjs
9 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require ('assert');
4 |
5 | const FL = require ('..');
6 |
7 |
8 | test ('exports', () => {
9 | assert.strictEqual (FL.map, 'fantasy-land/map');
10 | });
11 |
--------------------------------------------------------------------------------
/test/mocha.opts:
--------------------------------------------------------------------------------
1 | --ui tdd
2 |
--------------------------------------------------------------------------------