Specification for interoperability of common algebraic structures in JavaScript
(aka "Algebraic JavaScript Specification")
This project specifies interoperability of common algebraic structures:
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.
fantasy-land
package as a peer dependency. Add in your package.json
: ... "peerDependencies": "fantasy-land": "*" ...
fantasy-land
package exposes method names, you should use them for you Fantasy Land methods:var fl = // ... MyTypeprototypeflmap = { // Here goes implementation of map for your type... }
fantasy-land
as your normal dependecies: ... "dependencies": "some-fl-compatible-lib": "1.0.0" "fantasy-land": "1.0.0" ...
fantasy-land
package as well.If you do want to access Fantasy Land methods, do it like this:
var fl = var Something = var foo = 1var bar = fooflmap x + 1
a.equals(a) === true
(reflexivity)a.equals(b) === b.equals(a)
(symmetry)a.equals(b)
and b.equals(c)
, then a.equals(c)
(transitivity)equals
methodA 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
b
is not the same Setoid, behaviour of equals
is
unspecified (returning false
is recommended).equals
must return a boolean (true
or false
).
a.concat(b).concat(c)
is equivalent to a.concat(b.concat(c))
(associativity)concat
methodA 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
b
is not the same semigroup, behaviour of concat
is
unspecified.concat
must return a value of the same Semigroup.
A value that implements the Monoid specification must also implement the Semigroup specification.
m.concat(m.empty())
is equivalent to m
(right identity)m.empty().concat(m)
is equivalent to m
(left identity)empty
methodA 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 Monoidu.map(a => a)
is equivalent to u
(identity)u.map(x => f(g(x)))
is equivalent to u.map(g).map(f)
(composition)map
methodA value which has a Functor must provide a map
method. The map
method takes one argument:
u.map(f)
f
must be a function,
f
is not a function, the behaviour of map
is
unspecified.f
can return any value.map
must return a value of the same Functor
A value that implements the Apply specification must also implement the Functor specification.
a.map(f => g => x => f(g(x))).ap(u).ap(v)
is equivalent to a.ap(u.ap(v))
(composition)ap
methodA 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,
a
does not represent a function, the behaviour of ap
is
unspecified.b
must be an Apply of any value
ap
must apply the function in Apply a
to the value in
Apply b
A value that implements the Applicative specification must also implement the Apply specification.
a.of(x => x).ap(v)
is equivalent to v
(identity)a.of(f).ap(a.of(x))
is equivalent to a.of(f(x))
(homomorphism)u.ap(a.of(y))
is equivalent to a.of(f => f(y)).ap(u)
(interchange)of
methodA 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
b
should be checkedu.reduce
is equivalent to u.reduce((acc, x) => acc.concat([x]), []).reduce
reduce
methodA value which has a Foldable must provide a reduce
method. The reduce
method takes two arguments:
u.reduce(f, x)
f
must be a binary function
f
is not a function, the behaviour of reduce
is unspecified.f
must be the same type as x
.f
must return a value of the same type as x
x
is the initial accumulator value for the reduction
A value that implements the Traversable specification must also implement the Functor and Foldable specifications.
t(u.sequence(f.of))
is equivalent to u.map(t).sequence(g.of)
for any t
such that t(a).map(f)
is equivalent to t(a.map(f))
(naturality)
u.map(F.of).sequence(F.of)
is equivalent to F.of(u)
for any Applicative F
(identity)
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)
var { thisc = c;}; Compose { return F;}; Composeprototype { return thisc;}; Composeprototype { return thisc;};
sequence
methodA value which has a Traversable must provide a sequence
method. The sequence
method takes one argument:
u.sequence(of)
of
must return the Applicative that u
contains.A value that implements the Chain specification must also implement the Apply specification.
m.chain(f).chain(g)
is equivalent to m.chain(x => f(x).chain(g))
(associativity)chain
methodA 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
f
is not a function, the behaviour of chain
is
unspecified.f
must return a value of the same Chainchain
must return a value of the same Chain
A value that implements the Monad specification must also implement the Applicative and Chain specifications.
m.of(a).chain(f)
is equivalent to f(a)
(left identity)m.chain(m.of)
is equivalent to m
(right identity)w.extend(g).extend(f)
is equivalent to w.extend(_w => f(_w.extend(g)))
extend
methodAn Extend must provide an extend
method. The extend
method takes one argument:
w.extend(f)
f
must be a function which returns a value
f
is not a function, the behaviour of extend
is
unspecified.f
must return a value of type v
, for some variable v
contained in w
.extend
must return a value of the same Extend.
A value that implements the Comonad specification must also implement the Functor and Extend specifications.
w.extend(_w => _w.extract())
is equivalent to w
w.extend(f).extract()
is equivalent to f(w)
w.extend(f)
is equivalent to w.extend(x => x).map(f)
extract
methodA value which has a Comonad must provide an extract
method on itself.
The extract
method takes no arguments:
c.extract()
extract
must return a value of type v
, for some variable v
contained in w
.
v
must have the same type that f
returns in extend
.A value that implements the Bifunctor specification must also implement the Functor specification.
p.bimap(a => a, b => b)
is equivalent to p
(identity)p.bimap(a => f(g(a)), b => h(i(b))
is equivalent to p.bimap(g, i).bimap(f, h)
(composition)bimap
methodA value which has a Bifunctor must provide an bimap
method. The bimap
method takes two arguments:
c.bimap(f, g)
f
must be a function which returns a value
f
is not a function, the behaviour of bimap
is unspecified.f
can return any value.g
must be a function which returns a value
g
is not a function, the behaviour of bimap
is unspecified.g
can return any value.bimap
must return a value of the same Bifunctor.
A value that implements the Profunctor specification must also implement the Functor specification.
p.promap(a => a, b => b)
is equivalent to p
(identity)p.promap(a => f(g(a)), b => h(i(b)))
is equivalent to p.promap(f, i).promap(g, h)
(composition)promap
methodA value which has a Profunctor must provide a promap
method.
The profunctor
method takes two arguments:
c.promap(f, g)
f
must be a function which returns a value
f
is not a function, the behaviour of promap
is unspecified.f
can return any value.g
must be a function which returns a value
g
is not a function, the behaviour of promap
is unspecified.g
can return any value.promap
must return a value of the same Profunctor
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
:
{ return this; }
map
may be derived from chain
and of
:
{ var m = this; return m; }
map
may be derived from bimap
:
{ return this; }
map
may be derived from promap
:
{ return this; }
{ return this; }
reduce
may be derived as follows:
{ { thisvalue = value; } Const { return acc; }; Constprototype { return this; }; Constprototype { return ; }; return thisvalue;}
If a data type provides a method which could be derived, its behaviour must be equivalent to that of the derivation (or derivations).
Id
container which implements all methods is provided in
id.js
.