Skip to content

Commit

Permalink
Merge pull request #235 from gabejohnson/add-ord
Browse files Browse the repository at this point in the history
Add Ord spec
  • Loading branch information
davidchambers authored Apr 4, 2017
2 parents 3491c0f + 5a00508 commit 3af8d23
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 2 deletions.
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ structures:
* [Bifunctor](#bifunctor)
* [Profunctor](#profunctor)

<img src="figures/dependencies.png" width="888" height="289" />
<img src="figures/dependencies.png" width="888" height="294" />

## General

Expand Down Expand Up @@ -114,6 +114,33 @@ A value which has a Setoid must provide an `equals` method. The

2. `equals` must return a boolean (`true` or `false`).

### Ord

A value that implements the Ord specification must also implement
the [Setoid](#setoid) specification.

1. `a.lte(b)` or `b.lte(a)` (totality)
2. If `a.lte(b)` and `b.lte(a)`, then `a.equals(b)` (antisymmetry)
3. If `a.lte(b)` and `b.lte(c)`, then `a.lte(c)` (transitivity)

#### `lte` method

```hs
lte :: Ord a => a ~> a -> Boolean
```

A value which has an Ord must provide a `lte` method. The
`lte` method takes one argument:

a.lte(b)

1. `b` must be a value of the same Ord

1. If `b` is not the same Ord, behaviour of `lte` is
unspecified (returning `false` is recommended).

2. `lte` must return a boolean (`true` or `false`).

### Semigroup

1. `a.concat(b).concat(c)` is equivalent to `a.concat(b.concat(c))` (associativity)
Expand Down Expand Up @@ -605,6 +632,12 @@ The `profunctor` method takes two arguments:
When creating data types which satisfy multiple algebras, authors may choose
to implement certain methods then derive the remaining methods. Derivations:

- [`equals`][] may be derived from [`lte`][]:

```js
function(other) { return this.lte(other) && other.lte(this); }
```

- [`map`][] may be derived from [`ap`][] and [`of`][]:

```js
Expand Down Expand Up @@ -698,6 +731,7 @@ be equivalent to that of the derivation (or derivations).
[`equals`]: #equals-method
[`extend`]: #extend-method
[`extract`]: #extract-method
[`lte`]: #lte-method
[`map`]: #map-method
[`of`]: #of-method
[`promap`]: #promap-method
Expand Down
2 changes: 2 additions & 0 deletions figures/dependencies.dot
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ digraph {
Contravariant;
Monad;
Monoid;
Ord;
Plus;
Profunctor;
Semigroup;
Expand All @@ -40,4 +41,5 @@ digraph {
Functor -> Traversable;
Plus -> Alternative;
Semigroup -> Monoid;
Setoid -> Ord;
}
Binary file modified figures/dependencies.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

var mapping = {
equals: 'fantasy-land/equals',
lte: 'fantasy-land/lte',
concat: 'fantasy-land/concat',
empty: 'fantasy-land/empty',
map: 'fantasy-land/map',
Expand Down
8 changes: 8 additions & 0 deletions internal/func.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@

const fl = require('../');
const equality = (x, y) => typeof x[fl.equals] === 'function' ? x[fl.equals](y) : x === y;
const lte = (x, y) => {
if (typeof y[fl.lte] === 'function') return y[fl.lte](x);

const typeX = typeof x;
const typeY = typeof y;
return typeX === typeY && (typeX === 'string' || typeX === 'number') && x <= y;
};

module.exports = {
equality,
lte,
};
7 changes: 6 additions & 1 deletion internal/id.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

const fl = require('../');
const {equality} = require('./func');
const {equality, lte} = require('./func');

const {tagged} = require('daggy');

Expand All @@ -12,6 +12,11 @@ Id.prototype[fl.equals] = function(b) {
return equality(this.value, b.value);
};

// Ord
Id.prototype[fl.lte] = function(b) {
return lte(this.value, b.value);
};

// Semigroup (value must also be a Semigroup)
Id.prototype[fl.concat] = function(b) {
return new Id(this.value[fl.concat](b.value));
Expand Down
37 changes: 37 additions & 0 deletions laws/ord.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use strict';

const {lte, equals} = require('..');

/**
### Ord
1. `a.lte(b)` or `b.lte(a)` (totality)
2. If `a.lte(b)` and `b.lte(a)`, then `a.equals(b)` (antisymmetry)
3. If `a.lte(b)` and `b.lte(c)`, then `a.lte(c)` (transitivity)
**/

const totality = eq => f => g => {
const a = f[lte](g);
const b = g[lte](f);
const c = true;
return eq(a || b, c);
};

const antisymmetry = eq => f => g => {
const a = f[lte](g);
const b = g[lte](f);
const c = f[equals](g);
const d = true;
return eq(a, d) && eq(b, d) && eq(c, d);
};

const transitivity = eq => f => g => h => {
const a = f[lte](g);
const b = g[lte](h);
const c = f[lte](h);
const d = true;
return eq(a, d) && eq(b, d) && eq(c, d);
};

module.exports = {totality, antisymmetry, transitivity};
7 changes: 7 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const foldable = require('./laws/foldable');
const functor = require('./laws/functor');
const monad = require('./laws/monad');
const monoid = require('./laws/monoid');
const ord = require('./laws/ord');
const plus = require('./laws/plus');
const semigroup = require('./laws/semigroup');
const setoid = require('./laws/setoid');
Expand Down Expand Up @@ -98,6 +99,12 @@ exports.monoid = {
rightIdentity: test(monoid.rightIdentity(Sum)(equality)),
};

exports.ord = {
totality: test(() => ord.totality(equality)(Id[fl.of](1))(Id[fl.of](2))),
antisymmetry: test(() => ord.antisymmetry(equality)(Id[fl.of](1))(Id[fl.of](1))),
transitivity: test(() => ord.transitivity(equality)(Id[fl.of](1))(Id[fl.of](2))(Id[fl.of](3))),
};

exports.semigroup = {
associativity: test(semigroup.associativity(Id[fl.of])(equality)),
};
Expand Down

0 comments on commit 3af8d23

Please sign in to comment.