From 8586eb750c6fda88210ffc8302e44ce5fb7bf5e8 Mon Sep 17 00:00:00 2001 From: Brian McKenna Date: Thu, 11 Apr 2013 21:08:51 -0600 Subject: [PATCH] Let the fantasy begin --- README.md | 89 +++++++++++++++++++++++++++++++++++++++++++++ implementations.md | 9 +++++ logo.png | Bin 0 -> 11064 bytes 3 files changed, 98 insertions(+) create mode 100644 README.md create mode 100644 implementations.md create mode 100644 logo.png diff --git a/README.md b/README.md new file mode 100644 index 0000000..ee2e2e5 --- /dev/null +++ b/README.md @@ -0,0 +1,89 @@ +# Fantasy Land Specification + +(aka "Algebraic JavaScript Specification") + +![](logo.png) + +This project specifies interoperability of common algebraic +structures: + +* Functor +* Monad + +## General + +An algebra is a set of values, a set of operators that it is closed +under and some laws it must obey. + +## Terminology + +1. "value" is any JavaScript value, including any which have the + structures defined below. + +## Algebras + +### Functor + +1. `u.map(function(a) { return a; }))` equals `u` +2. `u.map(function(a) { return f(g(x)); })` equals `u.map(g).map(f)` + +#### `map` method + +A value which has a functor must provide a `map` method. The `map` +method takes one argument: + + u.map(f) + +1. `f` must be a function, + + 1. If `f` is not a function, the behaviour of `map` is + unspecified. + 2. `f` can return any value. + +2. `map` must return a value of the same functor + +### Monad + +A value which satisfies the specification of a monad do not need to implement: + +* Functor's `map`; derivable as `function(f) { var m = this; return + m.then(function(a) { return m.constructor.of(f(a)); })}` + +1. `of(a).then(f)` equals `f(a)` +2. `m.then(of)` equals `m` +3. `m.then(f).then(g)` equals `m.then(function(x) { return f(x).then(g); })` + +#### `then` method + +A value which has a monad must provide a `then` method. The `then` +method takes one argument: + + m.then(f) + +1. `f` must be a function which returns a value + + 1. If `f` is not a function, the behaviour of `then` is + unspecified. + 2. `f` must return a value of the same monad + +2. `then` must return a value of the same monad + +#### `constructor.of` method + +A value which has a monad must provide a `constructor` object. The +`constructor` object must have an `of` method which takes one +argument: + + m.constructor.of(a) + +1. `of` must provide a value of the same monad + + 1. No parts of `a` should be checked + +## Notes + +1. It's discouraged to overload the specified methods. It can easily + result in broken and buggy behaviour. +2. It is recommended to throw an exception on unspecified behaviour. +3. An `Id` container which implements all methods is provided in + `id.js`. diff --git a/implementations.md b/implementations.md new file mode 100644 index 0000000..79cf4a9 --- /dev/null +++ b/implementations.md @@ -0,0 +1,9 @@ +# Conformant Implementations + +Here are a list of implementations of the Fantasy Land specification: + +* ECMAScript 5 provides a Functor for Array + +Conforming implementations are encouraged to promote the Fantasy Land logo: + +![](logo.png) diff --git a/logo.png b/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..27388ebb4c535a9f0a7e97c473bc3635453e04be GIT binary patch literal 11064 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 RyhpjhD9dZeRmzwL{SVU>I3)l8 literal 0 HcmV?d00001