Skip to content

Commit

Permalink
Merge branch 'master' of github.com:fantasyland/fantasy-land
Browse files Browse the repository at this point in the history
* 'master' of github.com:fantasyland/fantasy-land:
  change spec to require prefixed names (fantasyland#146)
  • Loading branch information
rjmk committed Sep 6, 2016
2 parents c796a4e + 53e7504 commit cc8caee
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 107 deletions.
64 changes: 19 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,61 +47,35 @@ have dependencies on other algebras which must be implemented.
- Two promises are equivalent when they yield equivalent values.
- Two functions are equivalent if they yield equivalent outputs for equivalent inputs.

## How to add Fantasy Land compatibility to your library
## Prefixed method names

1. Add `fantasy-land` package as a peer dependency. Add in your `package.json`:
In order to add compatibility with Fantasy Land to your library,
you need to add methods that you want to support with `fantasy-land/` prefix.
For example if a type implements Functors' [`map`][], you need to add `fantasy-land/map` method to it.
The code may look something like this:

```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('fantasy-land')
// ...
```js
MyType.prototype['fantasy-land/map'] = MyType.prototype.map
```

MyType.prototype[fl.map] = function(fn) {
// Here goes implementation of map for your type...
}
```
It's not required to add unprefixed methods (e.g. `MyType.prototype.map`)
for compatibility with Fantasy Land, but you're free to do so of course.

## How to use Fantasy Land compatible library in your application
Further in this document unprefixed names are used just to reduce noise.

1. Add library npm package, and `fantasy-land` as your normal dependecies:
For convenience you can use `fantasy-land` package:

```js
{
...
"dependencies": {
"some-fl-compatible-lib": "1.0.0",
"fantasy-land": "1.0.0"
},
...
}
```
```js
var fl = reuire('fantasy-land')

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 `fantasy-land` package as well.
// ...

If you do want to access Fantasy Land methods, do it like this:
MyType.prototype[fl.map] = MyType.prototype.map

```js
var fl = require('fantasy-land')
var Something = require('some-fl-compatible-lib')
// ...

var foo = new Something(1)
var bar = foo[fl.map](x => x + 1)
```
var foo = bar[fl.map](x => x + 1)
```

## Algebras

Expand Down
36 changes: 18 additions & 18 deletions id_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,30 +58,30 @@ exports.chain = {
exports.chainRec = {
equivalence: test((x) => {
var predicate = a => a.length > 5
var done = Id.of
var next = a => Id.of(a.concat([x]))
var done = Id[of]
var next = a => Id[of](a.concat([x]))
var initial = [x]
return chainRec.equivalence(Id)(equality)(predicate)(done)(next)(initial)
})
};

exports.comonad = {
leftIdentity: test((x) => comonad.leftIdentity(Id.of)(equality)(x)),
rightIdentity: test((x) => comonad.rightIdentity(Id.of)(equality)(x)),
associativity: test((x) => comonad.associativity(Id.of)(equality)(x))
leftIdentity: test((x) => comonad.leftIdentity(Id[of])(equality)(x)),
rightIdentity: test((x) => comonad.rightIdentity(Id[of])(equality)(x)),
associativity: test((x) => comonad.associativity(Id[of])(equality)(x))
};

exports.extend = {
associativity: test((x) => extend.associativity(Id.of)(equality)(x))
associativity: test((x) => extend.associativity(Id[of])(equality)(x))
};

exports.foldable = {
associativity: test((x) => foldable.associativity(Id.of)(equality)(x))
associativity: test((x) => foldable.associativity(Id[of])(equality)(x))
};

exports.functor = {
identity: test((x) => functor.identity(Id.of)(equality)(x)),
composition: test((x) => functor.composition(Id.of)(equality)(x))
identity: test((x) => functor.identity(Id[of])(equality)(x)),
composition: test((x) => functor.composition(Id[of])(equality)(x))
};

exports.monad = {
Expand All @@ -90,22 +90,22 @@ exports.monad = {
};

exports.monoid = {
leftIdentity: test((x) => monoid.leftIdentity(Id.of(Sum.empty()))(equality)(Sum.of(x))),
rightIdentity: test((x) => monoid.rightIdentity(Id.of(Sum.empty()))(equality)(Sum.of(x)))
leftIdentity: test((x) => monoid.leftIdentity(Id[of](Sum[empty]()))(equality)(Sum[of](x))),
rightIdentity: test((x) => monoid.rightIdentity(Id[of](Sum[empty]()))(equality)(Sum[of](x)))
};

exports.semigroup = {
associativity: test((x) => semigroup.associativity(Id.of)(equality)(x))
associativity: test((x) => semigroup.associativity(Id[of])(equality)(x))
};

exports.setoid = {
reflexivity: test((x) => setoid.reflexivity(Id.of)(equality)(x)),
symmetry: test((x) => setoid.symmetry(Id.of)(equality)(x)),
transitivity: test((x) => setoid.transitivity(Id.of)(equality)(x))
reflexivity: test((x) => setoid.reflexivity(Id[of])(equality)(x)),
symmetry: test((x) => setoid.symmetry(Id[of])(equality)(x)),
transitivity: test((x) => setoid.transitivity(Id[of])(equality)(x))
};

exports.traversable = {
naturality: test((x) => traversable.naturality(Id.of)(equality)(Id.of(x))),
identity: test((x) => traversable.identity(Id.of)(equality)(x)),
composition: test((x) => traversable.composition(Id.of)(equality)(Id.of(Sum.of(x))))
naturality: test((x) => traversable.naturality(Id[of])(equality)(Id[of](x))),
identity: test((x) => traversable.identity(Id[of])(equality)(x)),
composition: test((x) => traversable.composition(Id[of])(equality)(Id[of](Sum[of](x))))
};
30 changes: 15 additions & 15 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
module.exports = {
equals: 'equals',
concat: 'concat',
empty: 'empty',
map: 'map',
contramap: 'contramap',
ap: 'ap',
of: 'of',
reduce: 'reduce',
sequence: 'sequence',
chain: 'chain',
chainRec: 'chainRec',
extend: 'extend',
extract: 'extract',
bimap: 'bimap',
promap: 'promap'
equals: 'fantasy-land/equals',
concat: 'fantasy-land/concat',
empty: 'fantasy-land/empty',
map: 'fantasy-land/map',
contramap: 'fantasy-land/contramap',
ap: 'fantasy-land/ap',
of: 'fantasy-land/of',
reduce: 'fantasy-land/reduce',
sequence: 'fantasy-land/sequence',
chain: 'fantasy-land/chain',
chainRec: 'fantasy-land/chainRec',
extend: 'fantasy-land/extend',
extract: 'fantasy-land/extract',
bimap: 'fantasy-land/bimap',
promap: 'fantasy-land/promap'
}
12 changes: 6 additions & 6 deletions laws/applicative.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,26 @@ const {of, ap} = require('..');
**/

const identityʹ = t => eq => x => {
const a = t[of](identity).ap(t[of](x));
const a = t[of](identity)[ap](t[of](x));
const b = t[of](x);
return eq(a, b);
};

const homomorphism = t => eq => x => {
const a = t[of](identity).ap(t[of](x));
const a = t[of](identity)[ap](t[of](x));
const b = t[of](identity(x));
return eq(a, b);
};

const interchange = t => eq => x => {
const u = t[of](identity);

const a = u.ap(t[of](x));
const b = t[of](thrush(x)).ap(u);
const a = u[ap](t[of](x));
const b = t[of](thrush(x))[ap](u);
return eq(a, b);
};

module.exports = { identity: identityʹ
, homomorphism
, interchange
};
, interchange
};
6 changes: 4 additions & 2 deletions laws/chainrec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use strict';

const {identity} = require('fantasy-combinators');
const {chain, map, chainRec} = require('..');


/**
Expand All @@ -13,8 +15,8 @@ const {identity} = require('fantasy-combinators');
**/

const equivalence = t => eq => p => d => n => x => {
const a = t.chainRec((next, done, v) => p(v) ? d(v).map(done) : n(v).map(next), x);
const b = (function step(v) { return p(v) ? d(v) : n(v).chain(step); }(x));
const a = t[chainRec]((next, done, v) => p(v) ? d(v)[map](done) : n(v)[map](next), x);
const b = (function step(v) { return p(v) ? d(v) : n(v)[chain](step); }(x));
return eq(a, b);
};

Expand Down
12 changes: 6 additions & 6 deletions laws/comonad.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

const {identity} = require('fantasy-combinators');
const {extend} = require('..');
const {extend, map, extract} = require('..');

/**
Expand All @@ -14,24 +14,24 @@ const {extend} = require('..');
**/

const leftIdentity = t => eq => x => {
const a = t(x).extend(identity).extract();
const a = t(x)[extend](identity)[extract]();
const b = t(x);
return eq(a, b);
};

const rightIdentity = t => eq => x => {
const a = t(x).extend(w => w.extract());
const a = t(x)[extend](w => w[extract]());
const b = t(x);
return eq(a, b);
};

const associativity = t => eq => x => {
const a = t(x).extend(identity);
const b = t(x).extend(identity).map(identity);
const a = t(x)[extend](identity);
const b = t(x)[extend](identity)[map](identity);
return eq(a, b);
};

module.exports = { leftIdentity
, rightIdentity
, associativity
};
};
6 changes: 3 additions & 3 deletions laws/extend.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ const {extend} = require('..');
**/

const associativity = t => eq => x => {
const a = t(x).extend(identity).extend(identity);
const b = t(x).extend(w => identity(w.extend(identity)));
const a = t(x)[extend](identity)[extend](identity);
const b = t(x)[extend](w => identity(w[extend](identity)));
return eq(a, b);
};

module.exports = { associativity };
module.exports = { associativity };
8 changes: 5 additions & 3 deletions laws/foldable.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use strict';

const {identity} = require('fantasy-combinators');
const {reduce} = require('..');


/**
Expand All @@ -11,9 +13,9 @@ const {identity} = require('fantasy-combinators');
**/

const associativity = t => eq => x => {
const a = t(x).reduce(identity, x);
const b = t(x).toArray().reduce(identity, x);
const a = t(x)[reduce](identity, x);
const b = t(x).toArray()[reduce](identity, x);
return eq(a, b);
};

module.exports = { associativity };
module.exports = { associativity };
21 changes: 12 additions & 9 deletions laws/traversable.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,26 @@ const {tagged} = require('daggy');
const Compose = tagged('c');
Compose[of] = Compose;
Compose.prototype[ap] = function(x) {
return Compose(this.c.map(u => y => u.ap(y)).ap(x.c));
return Compose(this.c[map](u => y => u[ap](y))[ap](x.c));
};
Compose.prototype[map] = function(f) {
return Compose(this.c[map](y => y[map](f)));
};
Compose.prototype[equals] = function(x) {
return this.c.equals ? this.c.equals(x.c) : this.c === x.c;
return this.c[equals] ? this.c[equals](x.c) : this.c === x.c;
};

Array.prototype[equals] = function(y) {
return this.length === y.length && this.join('') === y.join('');
};
Array.prototype.sequence = function(p) {
return this.reduce((ys, x) => {
return identity(x).map(y => z => {
return z.concat(y);
}).ap(ys);
Array.prototype[map] = Array.prototype.map
Array.prototype[reduce] = Array.prototype.reduce
Array.prototype[concat] = Array.prototype.concat
Array.prototype[sequence] = function(p) {
return this[reduce]((ys, x) => {
return identity(x)[map](y => z => {
return z[concat](y);
})[ap](ys);
}, p([]));
};

Expand Down Expand Up @@ -64,5 +67,5 @@ const composition = t => eq => x => {

module.exports = { naturality
, identity: identityʹ
, composition
};
, composition
};

0 comments on commit cc8caee

Please sign in to comment.