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. An algebra may also state other algebra methods which do not need to be implemented and how they can be derived from new methods.
fanatasy-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 = require'fanatasy-land' // ... MyTypeprototypeflmap = // Here goes implementation of map for your type...
fanatasy-land
as your normal dependecies: "dependencies": "some-fl-compatible-lib": "1.0.0" "fantasy-land": "1.0.0"
fanatasy-land
package as well.If you do want to access Fantasy Land methods, do it like this:
var fl = require'fanatasy-land'var Something = require'some-fl-compatible-lib' var foo = 1var bar = fooflmapx => 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 value which satisfies the specification of an Applicative does not need to implement:
map
; derivable as function(f) { return this.of(f).ap(this); }
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.toArray().reduce
toArray
; derivable as function() { return this.reduce((acc, x) => acc.concat([x]), []); }
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 specification.
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)
u.map(x => Id(x)).sequence(Id.of)
is equivalent to Id.of(u)
(identity)
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
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.
A value which satisfies the specification of a Chain does not need to implement:
ap
; derivable as function ap(m) { return this.chain(f => m.map(f)); }
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.
A value which satisfies the specification of a Monad does not need to implement:
ap
; derivable as function(m) { return this.chain(f => m.map(f)); }
map
; derivable as function(f) { var m = this; return m.chain(a => m.of(f(a)))}
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
.Id
container which implements all methods is provided in
id.js
.