- "value" is any JavaScript value, including any which have the structures defined below.
- "equivalent" is an appropriate definition of equivalence for the given value.
The definition should ensure that the two values can be safely swapped out in a program that respects abstractions. For example:
- Two lists are equivalent if they are equivalent at all indices.
- Two plain old JavaScript objects, interpreted as dictionaries, are equivalent when they are equivalent for all keys.
- Two promises are equivalent when they yield equivalent values.
- Two functions are equivalent if they yield equivalent outputs for equivalent inputs.
a.concat(b).concat(c)
is equivalent toa.concat(b.concat(c))
(associativity)
A value which has a Semigroup must provide a concat
method. The
concat
method takes one argument:
s.concat(b)
-
b
must be a value of the same Semigroup- If
b
is not the same semigroup, behaviour ofconcat
is unspecified.
- If
-
concat
must return a value of the same Semigroup.
A value that implements the Monoid specification must also implement the Semigroup specficiation.
m.concat(m.empty())
is equivalent tom
(right identity)m.empty().concat(m)
is equivalent tom
(left identity)
A value which has a Monoid must provide an empty
method on itself or
its constructor
object. The empty
method takes no arguments:
m.empty()
m.constructor.empty()
empty
must return a value of the same Monoid
u.map(function(a) { return a; }))
is equivalent tou
(identity)u.map(function(x) { return f(g(x)); })
is equivalent tou.map(g).map(f)
(composition)
A value which has a Functor must provide a map
method. The map
method takes one argument:
u.map(f)
-
f
must be a function,- If
f
is not a function, the behaviour ofmap
is unspecified. f
can return any value.
- If
-
map
must return a value of the same Functor
A value that implements the Applicative specification must also implement the Functor specification.
A value which satisfies the specification of a Applicative does not need to implement:
- Functor's
map
; derivable asfunction(f) { return this.of(f).ap(this); })}
a.of(function(a) { return a; }).ap(v)
is equivalent tov
(identity)a.of(function(f) { return function(g) { return function(x) { return f(g(x))}; }; }).ap(u).ap(v).ap(w)
is equivalent tou.ap(v.ap(w))
(composition)a.of(f).ap(a.of(x))
is equivalent toa.of(f(x))
(homomorphism)u.ap(a.of(y))
is equivalent toa.of(function(f) { return f(y); }).ap(u)
(interchange)
A value which has an Applicative must provide an ap
method. The ap
method takes one argument:
a.ap(b)
-
a
must be an Applicative of a function,- If
a
does not represent a function, the behaviour ofap
is unspecified.
- If
-
b
must be an Applicative of any value -
ap
must apply the function in Applicativea
to the value in Applicativeb
A value which has an Applicative must provide an of
method on itself
or its constructor
object. The of
method takes one argument:
a.of(b)
a.constructor.of(b)
-
of
must provide a value of the same Applicative- No parts of
b
should be checked
- No parts of
m.chain(f).chain(g)
is equivalent tom.chain(function(x) { return f(x).chain(g); })
(associativity)
A value which has a Chain must provide a chain
method. The chain
method takes one argument:
m.chain(f)
-
f
must be a function which returns a value- If
f
is not a function, the behaviour ofchain
is unspecified. f
must return a value of the same Chain
- If
-
chain
must return a value of the same Chain
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:
- Applicative's
ap
; derivable asfunction(m) { return this.chain(function(f) { return m.map(f); }); }
- Functor's
map
; derivable asfunction(f) { var m = this; return m.chain(function(a) { return m.of(f(a)); })}
m.of(a).chain(f)
is equivalent tof(a)
(left identity)m.chain(m.of)
is equivalent tom
(right identity)