Skip to content

Commit

Permalink
Add Group specification (#272)
Browse files Browse the repository at this point in the history
* add Group specification

* better property names

* back to inverse

* update dep chart

* follow already well established patterns for dat dot
  • Loading branch information
evilsoft authored and joneshf committed Oct 13, 2017
1 parent bc77629 commit 9d5eaa8
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 7 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ structures:
* [Category](#category)
* [Semigroup](#semigroup)
* [Monoid](#monoid)
* [Group](#group)
* [Functor](#functor)
* [Contravariant](#contravariant)
* [Apply](#apply)
Expand Down Expand Up @@ -306,6 +307,26 @@ Given a value `m`, one can access its type representative via the

1. `empty` must return a value of the same Monoid

### Group

A value that implements the Group specification must also implement
the [Monoid](#monoid) specification.

1. `g.concat(g.invert())` is equivalent to `g.empty()` (right inverse)
2. `g.invert().concat(g)` is equivalent to `g.empty()` (left inverse)

#### `invert` method

```hs
invert :: Group g => g ~> () -> g
```
A value which has a Group must provide an `invert` method. The
`invert` method takes no arguments:

g.invert()

1. `invert` must return a value of the same Group.

### Functor

1. `u.map(a => a)` is equivalent to `u` (identity)
Expand Down
2 changes: 2 additions & 0 deletions figures/dependencies.dot
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ digraph {
Extend;
Foldable;
Functor;
Group;
Contravariant;
Monad;
Monoid;
Expand Down Expand Up @@ -41,6 +42,7 @@ digraph {
Functor -> Extend;
Functor -> Profunctor;
Functor -> Traversable;
Monoid -> Group;
Plus -> Alternative;
Semigroup -> Monoid;
Semigroupoid -> Category;
Expand Down
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 @@ -12,6 +12,7 @@
id: 'fantasy-land/id',
concat: 'fantasy-land/concat',
empty: 'fantasy-land/empty',
invert: 'fantasy-land/invert',
map: 'fantasy-land/map',
contramap: 'fantasy-land/contramap',
ap: 'fantasy-land/ap',
Expand Down
2 changes: 1 addition & 1 deletion internal/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

const patch = require('./patch');
const Id = require('./id');
const Sum = require('./string_sum');
const Sum = require('./sum');
const Compose = require('./compose');
const {equality} = require('./func');

Expand Down
7 changes: 5 additions & 2 deletions internal/string_sum.js → internal/sum.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ const {tagged} = require('daggy');
const fl = require('..');
const {equality} = require('./func');

// Special type of sum for the type of string.
const Sum = module.exports = tagged('v');

Sum[fl.of] = Sum;
Sum[fl.empty] = () => Sum('');
Sum[fl.empty] = () => Sum(0);
Sum.prototype[fl.map] = function(f) {
return Sum(f(this.v));
};
Expand All @@ -18,3 +18,6 @@ Sum.prototype[fl.concat] = function(x) {
Sum.prototype[fl.equals] = function(x) {
return equality(this.v, x.v);
};
Sum.prototype[fl.invert] = function() {
return Sum(this.v >= 0 ? -Math.abs(this.v) : Math.abs(this.v));
};
30 changes: 30 additions & 0 deletions laws/group.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict';

const {of, empty, concat, invert} = require('..');

/**
### Group
1. `g.concat(g.invert())` is equivalent to `g.empty()` (right inverse)
2. `g.invert().concat(g)` is equivalent to `g.empty()` (left inverse)
**/

const rightInverse = T => eq => x => {
const g = T[of](x);

const a = g[concat](g[invert]());
const b = T[empty]();
return eq(a, b);
};

const leftInverse = T => eq => x => {
const g = T[of](x);

const a = g[invert]()[concat](g);
const b = T[empty]();
return eq(a, b);
};

module.exports = {rightInverse, leftInverse};
14 changes: 10 additions & 4 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const comonad = require('./laws/comonad');
const extend = require('./laws/extend');
const foldable = require('./laws/foldable');
const functor = require('./laws/functor');
const group = require('./laws/group');
const monad = require('./laws/monad');
const monoid = require('./laws/monoid');
const ord = require('./laws/ord');
Expand Down Expand Up @@ -90,6 +91,11 @@ exports.functor = {
composition: test(functor.composition(Id[fl.of])(equality)(a => [a, a])(a => [a])),
};

exports.group = {
rightInverse: test(() => group.rightInverse(Sum[fl.of])(equality)(42)),
leftInverse: test(() => group.leftInverse(Sum[fl.of])(equality)(42)),
};

exports.monad = {
leftIdentity: test(monad.leftIdentity(Id)(equality)(Id[fl.of])),
rightIdentity: test(monad.rightIdentity(Id)(equality)),
Expand All @@ -102,8 +108,8 @@ exports.plus = {
};

exports.monoid = {
leftIdentity: test(monoid.leftIdentity(Sum)(equality)),
rightIdentity: test(monoid.rightIdentity(Sum)(equality)),
leftIdentity: test(() => monoid.leftIdentity(Sum)(equality)(23)),
rightIdentity: test(() => monoid.rightIdentity(Sum)(equality)(23)),
};

exports.ord = {
Expand All @@ -117,7 +123,7 @@ exports.semigroup = {
};

exports.semigroupoid = {
associativity: semigroupoid.associativity(x => x + 1)(x => x * x)(x => x - 2)(equality)(5),
associativity: test(() => semigroupoid.associativity(x => x + 1)(x => x * x)(x => x - 2)(equality)(5)),
};

exports.setoid = {
Expand All @@ -129,5 +135,5 @@ exports.setoid = {
exports.traversable = {
naturality: test(x => traversable.naturality(Id)(Id[fl.of])(equality)(Id[fl.of](x))),
identity: test(traversable.identity(Id)(equality)),
composition: test(x => traversable.composition(Id)(Id[fl.of])(equality)(Id[fl.of](Sum[fl.of](x)))),
composition: test(() => traversable.composition(Id)(Id[fl.of])(equality)(Id[fl.of](Sum[fl.of](37)))),
};

0 comments on commit 9d5eaa8

Please sign in to comment.