diff --git a/README.md b/README.md index e0b17f3..a41e663 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,7 @@ An algebra is a set of values, a set of operators that it is closed under and some laws it must obey. 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. ## Terminology @@ -101,7 +99,6 @@ implemented and how they can be derived from new methods. var bar = foo[fl.map](x => x + 1) ``` - ## Algebras ### Setoid @@ -209,11 +206,6 @@ method takes one argument: A value that implements the Applicative specification must also implement the Apply specification. -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) 2. `a.of(f).ap(a.of(x))` is equivalent to `a.of(f(x))` (homomorphism) 3. `u.ap(a.of(y))` is equivalent to `a.of(f => f(y)).ap(u)` (interchange) @@ -234,8 +226,6 @@ or its `constructor` object. The `of` method takes one argument: 1. `u.reduce` is equivalent to `u.toArray().reduce` -* `toArray`; derivable as `function() { return this.reduce((acc, x) => acc.concat([x]), []); }` - #### `reduce` method A value which has a Foldable must provide a `reduce` method. The `reduce` @@ -264,8 +254,6 @@ where `t` is a natural transformation from `f` to `g` (naturality) 3. `u.map(Compose).sequence(Compose.of)` is equivalent to `Compose(u.sequence(f.of).map(x => x.sequence(g.of)))` (composition) -* `traverse`; derivable as `function(f, of) { return this.map(f).sequence(of); }` - #### `sequence` method A value which has a Traversable must provide a `sequence` method. The `sequence` @@ -280,11 +268,6 @@ method takes one argument: A value that implements the Chain specification must also implement the Apply specification. -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) #### `chain` method @@ -307,12 +290,6 @@ method takes one argument: A value that implements the Monad specification must also implement the Applicative and Chain specifications. -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) 2. `m.chain(m.of)` is equivalent to `m` (right identity) @@ -353,12 +330,22 @@ The `extract` method takes no arguments: 1. `extract` must return a value of type `v`, for some variable `v` contained in `w`. 1. `v` must have the same type that `f` returns in `extend`. +## 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`][]: + function(f) { return this.of(f).ap(this); } + - [`map`][] may be derived from [`chain`][] and [`of`][]: + function(f) { var m = this; return m.chain(a => m.of(f(a))); } + - [`ap`][] may be derived from [`chain`][]: + + function(m) { return this.chain(f => m.map(f)); } ## Notes @@ -370,3 +357,16 @@ The `extract` method takes no arguments: 3. It is recommended to throw an exception on unspecified behaviour. 4. An `Id` container which implements all methods is provided in `id.js`. + + +[`ap`]: #ap-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 +[`reduce`]: #reduce-method +[`sequence`]: #sequence-method