fantasy-land
Advanced tools
Comparing version 0.2.1 to 0.3.0
@@ -12,3 +12,5 @@ module.exports = { | ||
extend: 'extend', | ||
extract: 'extract' | ||
extract: 'extract', | ||
bimap: 'bimap', | ||
promap: 'promap' | ||
} |
{ | ||
"name": "fantasy-land", | ||
"author": "Brian McKenna", | ||
"version": "0.2.1", | ||
"version": "0.3.0", | ||
"description": "Specification for interoperability of common algebraic structures in JavaScript", | ||
@@ -6,0 +6,0 @@ "license": "MIT", |
186
README.md
@@ -24,2 +24,4 @@ # Fantasy Land Specification | ||
* [Comonad](#comonad) | ||
* [Bifunctor](#bifunctor) | ||
* [Profunctor](#profunctor) | ||
@@ -34,5 +36,3 @@ <img src="figures/dependencies.png" width="677" height="212" /> | ||
Each Fantasy Land algebra is a separate specification. An algebra may | ||
have dependencies on other algebras which must be implemented. An | ||
algebra may also state other algebra methods which do not need to be | ||
implemented and how they can be derived from new methods. | ||
have dependencies on other algebras which must be implemented. | ||
@@ -52,3 +52,3 @@ ## Terminology | ||
1. Add `fanatasy-land` package as a peer dependency. Add in your `package.json`: | ||
1. Add `fantasy-land` package as a peer dependency. Add in your `package.json`: | ||
@@ -68,3 +68,3 @@ ```js | ||
```js | ||
var fl = require('fanatasy-land') | ||
var fl = require('fantasy-land') | ||
@@ -80,3 +80,3 @@ // ... | ||
1. Add library npm package, and `fanatasy-land` as your normal dependecies: | ||
1. Add library npm package, and `fantasy-land` as your normal dependecies: | ||
@@ -97,3 +97,3 @@ ```js | ||
then that's it — simply install them and use as you normally would, | ||
only install `fanatasy-land` package as well. | ||
only install `fantasy-land` package as well. | ||
@@ -103,3 +103,3 @@ If you do want to access Fantasy Land methods, do it like this: | ||
```js | ||
var fl = require('fanatasy-land') | ||
var fl = require('fantasy-land') | ||
var Something = require('some-fl-compatible-lib') | ||
@@ -111,3 +111,2 @@ | ||
## Algebras | ||
@@ -220,7 +219,2 @@ | ||
A value which satisfies the specification of an Applicative does not | ||
need to implement: | ||
* Functor's `map`; derivable as `function(f) { return this.of(f).ap(this); }` | ||
1. `a.of(x => x).ap(v)` is equivalent to `v` (identity) | ||
@@ -244,6 +238,4 @@ 2. `a.of(f).ap(a.of(x))` is equivalent to `a.of(f(x))` (homomorphism) | ||
1. `u.reduce` is equivalent to `u.toArray().reduce` | ||
1. `u.reduce` is equivalent to `u.reduce((acc, x) => acc.concat([x]), []).reduce` | ||
* `toArray`; derivable as `function() { return this.reduce((acc, x) => acc.concat([x]), []); }` | ||
#### `reduce` method | ||
@@ -267,14 +259,30 @@ | ||
A value that implements the Traversable specification must also | ||
implement the Functor specification. | ||
implement the Functor and Foldable specifications. | ||
1. `t(u.sequence(f.of))` is equivalent to `u.map(t).sequence(g.of)` | ||
where `t` is a natural transformation from `f` to `g` (naturality) | ||
for any `t` such that `t(a).map(f)` is equivalent to `t(a.map(f))` (naturality) | ||
2. `u.map(x => Id(x)).sequence(Id.of)` is equivalent to `Id.of(u)` (identity) | ||
2. `u.map(F.of).sequence(F.of)` is equivalent to `F.of(u)` for any Applicative `F` (identity) | ||
3. `u.map(Compose).sequence(Compose.of)` is equivalent to | ||
`Compose(u.sequence(f.of).map(x => x.sequence(g.of)))` (composition) | ||
3. `u.map(x => new Compose(x)).sequence(Compose.of)` is equivalent to | ||
`new Compose(u.sequence(F.of).map(v => v.sequence(G.of)))` for `Compose` defined below and any Applicatives `F` and `G` (composition) | ||
* `traverse`; derivable as `function(f, of) { return this.map(f).sequence(of); }` | ||
```js | ||
var Compose = function(c) { | ||
this.c = c; | ||
}; | ||
Compose.of = function(x) { | ||
return new Compose(F.of(G.of(x))); | ||
}; | ||
Compose.prototype.ap = function(x) { | ||
return new Compose(this.c.map(u => y => u.ap(y)).ap(x.c)); | ||
}; | ||
Compose.prototype.map = function(f) { | ||
return new Compose(this.c.map(y => y.map(f))); | ||
}; | ||
``` | ||
#### `sequence` method | ||
@@ -294,7 +302,2 @@ | ||
A value which satisfies the specification of a Chain does not | ||
need to implement: | ||
* Apply's `ap`; derivable as `function ap(m) { return this.chain(f => m.map(f)); }` | ||
1. `m.chain(f).chain(g)` is equivalent to `m.chain(x => f(x).chain(g))` (associativity) | ||
@@ -322,8 +325,2 @@ | ||
A value which satisfies the specification of a Monad does not need to | ||
implement: | ||
* Apply's `ap`; derivable as `function(m) { return this.chain(f => m.map(f)); }` | ||
* Functor's `map`; derivable as `function(f) { var m = this; return m.chain(a => m.of(f(a)))}` | ||
1. `m.of(a).chain(f)` is equivalent to `f(a)` (left identity) | ||
@@ -369,9 +366,115 @@ 2. `m.chain(m.of)` is equivalent to `m` (right identity) | ||
### Bifunctor | ||
A value that implements the Bifunctor specification must also implement | ||
the Functor specification. | ||
1. `p.bimap(a => a, b => b)` is equivalent to `p` (identity) | ||
2. `p.bimap(a => f(g(a)), b => h(i(b))` is equivalent to `p.bimap(g, i).bimap(f, h)` (composition) | ||
#### `bimap` method | ||
A value which has a Bifunctor must provide an `bimap` method. The `bimap` | ||
method takes two arguments: | ||
c.bimap(f, g) | ||
1. `f` must be a function which returns a value | ||
1. If `f` is not a function, the behaviour of `bimap` is unspecified. | ||
2. `f` can return any value. | ||
2. `g` must be a function which returns a value | ||
1. If `g` is not a function, the behaviour of `bimap` is unspecified. | ||
2. `g` can return any value. | ||
3. `bimap` must return a value of the same Bifunctor. | ||
### Profunctor | ||
A value that implements the Profunctor specification must also implement | ||
the Functor specification. | ||
1. `p.promap(a => a, b => b)` is equivalent to `p` (identity) | ||
2. `p.promap(a => f(g(a)), b => h(i(b)))` is equivalent to `p.promap(f, i).promap(g, h)` (composition) | ||
#### `promap` method | ||
A value which has a Profunctor must provide a `promap` method. | ||
The `profunctor` method takes two arguments: | ||
c.promap(f, g) | ||
1. `f` must be a function which returns a value | ||
1. If `f` is not a function, the behaviour of `promap` is unspecified. | ||
2. `f` can return any value. | ||
2. `g` must be a function which returns a value | ||
1. If `g` is not a function, the behaviour of `promap` is unspecified. | ||
2. `g` can return any value. | ||
3. `promap` must return a value of the same Profunctor | ||
## Derivations | ||
When creating data types which satisfy multiple algebras, authors may choose | ||
to implement certain methods then derive the remaining methods. Derivations: | ||
- [`map`][] may be derived from [`ap`][] and [`of`][]: | ||
```js | ||
function(f) { return this.of(f).ap(this); } | ||
``` | ||
- [`map`][] may be derived from [`chain`][] and [`of`][]: | ||
```js | ||
function(f) { var m = this; return m.chain(a => m.of(f(a))); } | ||
``` | ||
- [`map`][] may be derived from [`bimap`]: | ||
```js | ||
function(f) { return this.bimap(a => a, f); } | ||
``` | ||
- [`map`][] may be derived from [`promap`]: | ||
```js | ||
function(f) { return this.promap(a => a, f); } | ||
``` | ||
- [`ap`][] may be derived from [`chain`][]: | ||
```js | ||
function(m) { return this.chain(f => m.map(f)); } | ||
``` | ||
- [`reduce`][] may be derived as follows: | ||
```js | ||
function(f, acc) { | ||
function Const(value) { | ||
this.value = value; | ||
} | ||
Const.of = function(_) { | ||
return new Const(acc); | ||
}; | ||
Const.prototype.map = function(_) { | ||
return this; | ||
}; | ||
Const.prototype.ap = function(b) { | ||
return new Const(f(this.value, b.value)); | ||
}; | ||
return this.map(x => new Const(x)).sequence(Const.of).value; | ||
} | ||
``` | ||
If a data type provides a method which *could* be derived, its behaviour must | ||
be equivalent to that of the derivation (or derivations). | ||
## Notes | ||
@@ -387,1 +490,16 @@ | ||
`id.js`. | ||
[`ap`]: #ap-method | ||
[`bimap`]: #bimap-method | ||
[`chain`]: #chain-method | ||
[`concat`]: #concat-method | ||
[`empty`]: #empty-method | ||
[`equals`]: #equals-method | ||
[`extend`]: #extend-method | ||
[`extract`]: #extract-method | ||
[`map`]: #map-method | ||
[`of`]: #of-method | ||
[`promap`]: #promap-method | ||
[`reduce`]: #reduce-method | ||
[`sequence`]: #sequence-method |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
26902
19
375
491
0