fantasy-land
Advanced tools
Comparing version 0.1.0 to 0.2.0
55
id.js
@@ -0,1 +1,3 @@ | ||
var fl = require('./') | ||
function Id(a) { | ||
@@ -6,36 +8,63 @@ this.value = a; | ||
// Setoid | ||
Id.prototype.equals = function (b) { | ||
return typeof this.value.equals === "function" ? this.value.equals(b.value) : this.value === b.value; | ||
Id.prototype[fl.equals] = function(b) { | ||
return typeof this.value[fl.equals] === "function" ? this.value[fl.equals](b.value) : this.value === b.value; | ||
}; | ||
// Semigroup (value must also be a Semigroup) | ||
Id.prototype.concat = function(b) { | ||
return new Id(this.value.concat(b.value)); | ||
Id.prototype[fl.concat] = function(b) { | ||
return new Id(this.value[fl.concat](b.value)); | ||
}; | ||
// Monoid (value must also be a Monoid) | ||
Id.prototype.empty = function() { | ||
return new Id(this.value.empty ? this.value.empty() : this.value.constructor.empty()); | ||
Id[fl.empty] = function() { | ||
return new Id(this.value[fl.empty] ? this.value[fl.empty]() : this.value.constructor[fl.empty]()); | ||
}; | ||
Id.prototype[fl.empty] = Id[fl.empty]; | ||
// Foldable | ||
Id.prototype[fl.reduce] = function(f, acc) { | ||
return f(acc, this.value); | ||
}; | ||
Id.prototype.toArray = function() { | ||
return [this.value]; | ||
}; | ||
// Functor | ||
Id.prototype.map = function(f) { | ||
Id.prototype[fl.map] = function(f) { | ||
return new Id(f(this.value)); | ||
}; | ||
// Applicative | ||
Id.prototype.ap = function(b) { | ||
// Apply | ||
Id.prototype[fl.ap] = function(b) { | ||
return new Id(this.value(b.value)); | ||
}; | ||
// Traversable | ||
Id.prototype[fl.sequence] = function(of) { | ||
// the of argument is only provided for types where map might fail. | ||
return this.value.map(Id[fl.of]); | ||
}; | ||
// Chain | ||
Id.prototype.chain = function(f) { | ||
Id.prototype[fl.chain] = function(f) { | ||
return f(this.value); | ||
}; | ||
// Monad | ||
Id.of = function(a) { | ||
// Extend | ||
Id.prototype[fl.extend] = function(f) { | ||
return new Id(f(this)); | ||
}; | ||
// Applicative | ||
Id[fl.of] = function(a) { | ||
return new Id(a); | ||
}; | ||
Id.prototype[fl.of] = Id[fl.of]; | ||
if(typeof module == 'object') module.exports = Id; | ||
// Comonad | ||
Id.prototype[fl.extract] = function() { | ||
return this.value; | ||
}; | ||
module.exports = Id; |
{ | ||
"name": "fantasy-land", | ||
"author": "Brian McKenna", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "Specification for interoperability of common algebraic structures in JavaScript", | ||
"license": "XXX", | ||
"license": "MIT", | ||
"homepage": "https://github.com/fantasyland/fantasy-land", | ||
@@ -21,2 +21,9 @@ "keywords": [ | ||
}, | ||
"dependencies": { | ||
"daggy": "0.0.x", | ||
"fantasy-combinators": "0.0.x" | ||
}, | ||
"devDependencies": { | ||
"nodeunit": "0.9.x" | ||
}, | ||
"repository": { | ||
@@ -27,4 +34,9 @@ "type": "git", | ||
"files": [ | ||
"id.js" | ||
] | ||
"id.js", | ||
"index.js" | ||
], | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "node --harmony_destructuring node_modules/.bin/nodeunit id_test.js" | ||
} | ||
} |
189
README.md
# Fantasy Land Specification | ||
[![Join the chat at https://gitter.im/fantasyland/fantasy-land](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fantasyland/fantasy-land?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | ||
(aka "Algebraic JavaScript Specification") | ||
![](logo.png) | ||
<img src="logo.png" width="200" height="200" /> | ||
@@ -10,12 +12,16 @@ This project specifies interoperability of common algebraic | ||
* Setoid | ||
* Semigroup | ||
* Monoid | ||
* Functor | ||
* Apply | ||
* Applicative | ||
* Chain | ||
* Monad | ||
* [Setoid](#setoid) | ||
* [Semigroup](#semigroup) | ||
* [Monoid](#monoid) | ||
* [Functor](#functor) | ||
* [Apply](#apply) | ||
* [Applicative](#applicative) | ||
* [Foldable](#foldable) | ||
* [Traversable](#traversable) | ||
* [Chain](#chain) | ||
* [Monad](#monad) | ||
* [Extend](#extend) | ||
* [Comonad](#comonad) | ||
![](figures/dependencies.png) | ||
<img src="figures/dependencies.png" width="677" height="212" /> | ||
@@ -43,2 +49,59 @@ ## General | ||
## How to add Fantasy Land compatibility to your library | ||
1. Add `fanatasy-land` package as a peer dependency. Add in your `package.json`: | ||
```js | ||
{ | ||
... | ||
"peerDependencies": { | ||
"fantasy-land": "*" | ||
}, | ||
... | ||
} | ||
``` | ||
2. The `fantasy-land` package exposes method names, you should use them for you Fantasy Land methods: | ||
```js | ||
var fl = require('fanatasy-land') | ||
// ... | ||
MyType.prototype[fl.map] = function(fn) { | ||
// Here goes implementation of map for your type... | ||
} | ||
``` | ||
## How to use Fantasy Land compatible library in your application | ||
1. Add library npm package, and `fanatasy-land` as your normal dependecies: | ||
```js | ||
{ | ||
... | ||
"dependencies": { | ||
"some-fl-compatible-lib": "1.0.0", | ||
"fantasy-land": "1.0.0" | ||
}, | ||
... | ||
} | ||
``` | ||
2. If you don't want to access Fantasy Land methods directly | ||
(for example if you use two libraries that talk to each other using Fantasy Land), | ||
then that's it — simply install them and use as you normally would, | ||
only install `fanatasy-land` package as well. | ||
If you do want to access Fantasy Land methods, do it like this: | ||
```js | ||
var fl = require('fanatasy-land') | ||
var Something = require('some-fl-compatible-lib') | ||
var foo = new Something(1) | ||
var bar = foo[fl.map](x => x + 1) | ||
``` | ||
## Algebras | ||
@@ -87,3 +150,3 @@ | ||
A value that implements the Monoid specification must also implement | ||
the Semigroup specficiation. | ||
the Semigroup specification. | ||
@@ -105,4 +168,4 @@ 1. `m.concat(m.empty())` is equivalent to `m` (right identity) | ||
1. `u.map(function(a) { return a; }))` is equivalent to `u` (identity) | ||
2. `u.map(function(x) { return f(g(x)); })` is equivalent to `u.map(g).map(f)` (composition) | ||
1. `u.map(a => a)` is equivalent to `u` (identity) | ||
2. `u.map(x => f(g(x)))` is equivalent to `u.map(g).map(f)` (composition) | ||
@@ -129,3 +192,3 @@ #### `map` method | ||
1. `a.map(function(f) { return function(g) { return function(x) { return f(g(x))}; }; }).ap(u).ap(v)` is equivalent to `a.ap(u.ap(v))` (composition) | ||
1. `a.map(f => g => x => f(g(x))).ap(u).ap(v)` is equivalent to `a.ap(u.ap(v))` (composition) | ||
@@ -157,7 +220,7 @@ #### `ap` method | ||
* Functor's `map`; derivable as `function(f) { return this.of(f).ap(this); })}` | ||
* Functor's `map`; derivable as `function(f) { return this.of(f).ap(this); }` | ||
1. `a.of(function(a) { return a; }).ap(v)` is equivalent to `v` (identity) | ||
1. `a.of(x => x).ap(v)` is equivalent to `v` (identity) | ||
2. `a.of(f).ap(a.of(x))` is equivalent to `a.of(f(x))` (homomorphism) | ||
3. `u.ap(a.of(y))` is equivalent to `a.of(function(f) { return f(y); }).ap(u)` (interchange) | ||
3. `u.ap(a.of(y))` is equivalent to `a.of(f => f(y)).ap(u)` (interchange) | ||
@@ -176,2 +239,47 @@ #### `of` method | ||
### Foldable | ||
1. `u.reduce` is equivalent to `u.toArray().reduce` | ||
* `toArray`; derivable as `function() { return this.reduce((acc, x) => acc.concat([x]), []); }` | ||
#### `reduce` method | ||
A value which has a Foldable must provide a `reduce` method. The `reduce` | ||
method takes two arguments: | ||
u.reduce(f, x) | ||
1. `f` must be a binary function | ||
1. if `f` is not a function, the behaviour of `reduce` is unspecified. | ||
2. The first argument to `f` must be the same type as `x`. | ||
3. `f` must return a value of the same type as `x` | ||
1. `x` is the initial accumulator value for the reduction | ||
### Traversable | ||
A value that implements the Traversable specification must also | ||
implement the Functor specification. | ||
1. `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) | ||
2. `u.map(x => Id(x)).sequence(Id.of)` is equivalent to `Id.of(u)` (identity) | ||
3. `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` method | ||
A value which has a Traversable must provide a `sequence` method. The `sequence` | ||
method takes one argument: | ||
u.sequence(of) | ||
1. `of` must return the Applicative that `u` contains. | ||
### Chain | ||
@@ -185,5 +293,5 @@ | ||
* Apply's `ap`; derivable as `m.chain(function(f) { return m.map(f); })` | ||
* Apply's `ap`; derivable as `function ap(m) { return this.chain(f => m.map(f)); }` | ||
1. `m.chain(f).chain(g)` is equivalent to `m.chain(function(x) { return f(x).chain(g); })` (associativity) | ||
1. `m.chain(f).chain(g)` is equivalent to `m.chain(x => f(x).chain(g))` (associativity) | ||
@@ -213,4 +321,4 @@ #### `chain` method | ||
* Apply's `ap`; derivable as `function(m) { return this.chain(function(f) { return m.map(f); }); }` | ||
* Functor's `map`; derivable as `function(f) { var m = this; return m.chain(function(a) { return m.of(f(a)); })}` | ||
* Apply's `ap`; derivable as `function(m) { return this.chain(f => m.map(f)); }` | ||
* Functor's `map`; derivable as `function(f) { var m = this; return m.chain(a => m.of(f(a)))}` | ||
@@ -220,7 +328,46 @@ 1. `m.of(a).chain(f)` is equivalent to `f(a)` (left identity) | ||
### Extend | ||
1. `w.extend(g).extend(f)` is equivalent to `w.extend(_w => f(_w.extend(g)))` | ||
#### `extend` method | ||
An Extend must provide an `extend` method. The `extend` | ||
method takes one argument: | ||
w.extend(f) | ||
1. `f` must be a function which returns a value | ||
1. If `f` is not a function, the behaviour of `extend` is | ||
unspecified. | ||
2. `f` must return a value of type `v`, for some variable `v` contained in `w`. | ||
2. `extend` must return a value of the same Extend. | ||
### Comonad | ||
A value that implements the Comonad specification must also implement the Functor and Extend specifications. | ||
1. `w.extend(_w => _w.extract())` is equivalent to `w` | ||
2. `w.extend(f).extract()` is equivalent to `f(w)` | ||
3. `w.extend(f)` is equivalent to `w.extend(x => x).map(f)` | ||
#### `extract` method | ||
A value which has a Comonad must provide an `extract` method on itself. | ||
The `extract` method takes no arguments: | ||
c.extract() | ||
1. `extract` must return a value of type `v`, for some variable `v` contained in `w`. | ||
1. `v` must have the same type that `f` returns in `extend`. | ||
## Notes | ||
@@ -227,0 +374,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Misc. License Issues
License(Experimental) A package's licensing information has fine-grained problems.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No License Found
License(Experimental) License information could not be found.
Found 1 instance in 1 package
14091
5
0
0
67
373
2
1
+ Addeddaggy@0.0.x
+ Addedfantasy-combinators@0.0.x
+ Addeddaggy@0.0.1(transitive)
+ Addedfantasy-combinators@0.0.1(transitive)