Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change spec to require prefixed names #146

Merged
merged 1 commit into from
Sep 6, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 19 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,61 +46,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))))
};
28 changes: 14 additions & 14 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
module.exports = {
equals: 'equals',
concat: 'concat',
empty: 'empty',
map: 'map',
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',
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
};