fantasyland
Specification for interoperability of common algebraic structures in JavaScript
Fantasy Land Specification
(aka "Algebraic JavaScript Specification")
This project specifies interoperability of common algebraic structures:
 Setoid
 Semigroup
 Monoid
 Functor
 Apply
 Applicative
 Chain
 Monad
General
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.
Terminology
 "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.
Algebras
Setoid
a.equals(a) === true
(reflexivity)a.equals(b) === b.equals(a)
(symmetry) If
a.equals(b)
andb.equals(c)
, thena.equals(c)
(transitivity)
equals
method
A value which has a Setoid must provide an equals
method. The
equals
method takes one argument:
a.equals(b)

b
must be a value of the same Setoid If
b
is not the same Setoid, behaviour ofequals
is unspecified (returningfalse
is recommended).
 If

equals
must return a boolean (true
orfalse
).
Semigroup
a.concat(b).concat(c)
is equivalent toa.concat(b.concat(c))
(associativity)
concat
method
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.
Monoid
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)
empty
method
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
Functor
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)
map
method
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
Apply
A value that implements the Apply specification must also implement the Functor specification.
a.map(function(f) { return function(g) { return function(x) { return f(g(x))}; }; }).ap(u).ap(v)
is equivalent toa.ap(u.ap(v))
(composition)
ap
method
A value which has an Apply must provide an ap
method. The ap
method takes one argument:
a.ap(b)

a
must be an Apply of a function, If
a
does not represent a function, the behaviour ofap
is unspecified.
 If

b
must be an Apply of any value 
ap
must apply the function in Applya
to the value in Applyb
Applicative
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 asfunction(f) { return this.of(f).ap(this); })}
a.of(function(a) { return a; }).ap(v)
is equivalent tov
(identity)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)
of
method
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
Chain
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 asm.chain(function(f) { return m.map(f); })
m.chain(f).chain(g)
is equivalent tom.chain(function(x) { return f(x).chain(g); })
(associativity)
chain
method
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
Monad
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 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)
Notes
 If there's more than a single way to implement the methods and laws, the implementation should choose one and provide wrappers for other uses.
 It's discouraged to overload the specified methods. It can easily result in broken and buggy behaviour.
 It is recommended to throw an exception on unspecified behaviour.
 An
Id
container which implements all methods is provided inid.js
.