Skip to content

Commit

Permalink
use fantasy-laws
Browse files Browse the repository at this point in the history
  • Loading branch information
davidchambers committed Apr 30, 2018
1 parent 482da54 commit 7a64a83
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 31 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
}
},
{
"files": ["test/*.js"],
"files": ["test/**/*.js"],
"rules": {
"comma-dangle": ["error", "always-multiline"],
"func-call-spacing": ["error", "always", {"allowNewlines": true}],
"func-style": ["error", "declaration", {"allowArrowFunctions": true}],
"indent": ["off"],
Expand Down
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
],
"dependencies": {
"sanctuary-show": "1.0.x",
"sanctuary-type-classes": "7.1.x"
"sanctuary-type-classes": "8.2.0"
},
"ignore": [
"/.circleci/",
Expand Down
16 changes: 2 additions & 14 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,10 @@
//. - [Applicative][]
//. - [Chain][]
//. - [Monad][]
//. - [Alt][] (if `a` satisfies Alt)
//. - [Foldable][]
//. - [Traversable][]
//. - [Extend][]
//. - [Extract][]
//. - [Comonad][]

(function(f) {

Expand Down Expand Up @@ -150,16 +149,6 @@
return f(this.value);
};

//# Identity#fantasy-land/alt :: Alt a => Identity a ~> Identity a -> Identity a
//.
//. ```javascript
//. > Z.alt(Identity([1, 2, 3]), Identity([4, 5, 6]))
//. Identity([1, 2, 3, 4, 5, 6])
//. ```
Identity.prototype['fantasy-land/alt'] = function(other) {
return Identity(Z.alt(this.value, other.value));
};

//# Identity#fantasy-land/reduce :: Identity a ~> ((b, a) -> b, b) -> b
//.
//. ```javascript
Expand Down Expand Up @@ -215,12 +204,11 @@

}));

//. [Alt]: v:fantasyland/fantasy-land#alt
//. [Applicative]: v:fantasyland/fantasy-land#applicative
//. [Apply]: v:fantasyland/fantasy-land#apply
//. [Chain]: v:fantasyland/fantasy-land#chain
//. [Comonad]: v:fantasyland/fantasy-land#comonad
//. [Extend]: v:fantasyland/fantasy-land#extend
//. [Extract]: v:fantasyland/fantasy-land#extract
//. [Fantasy Land]: v:fantasyland/fantasy-land
//. [Foldable]: v:fantasyland/fantasy-land#foldable
//. [Functor]: v:fantasyland/fantasy-land#functor
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
},
"dependencies": {
"sanctuary-show": "1.0.x",
"sanctuary-type-classes": "7.1.x"
"sanctuary-type-classes": "8.2.0"
},
"devDependencies": {
"fantasy-land": "3.4.0",
Expand Down
202 changes: 188 additions & 14 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,43 @@ function eq(actual) {
// IdentityArb :: Arbitrary a -> Arbitrary (Identity a)
const IdentityArb = arb => arb.smap (Identity, value, show);

// NonEmpty :: Arbitrary a -> Arbitrary (NonEmpty a)
const NonEmpty = arb => jsc.suchthat (arb, x => not (empty (x)));

// NumberArb :: Arbitrary Number
const NumberArb = jsc.oneof (
jsc.constant (NaN),
jsc.constant (-Infinity),
jsc.constant (Number.MIN_SAFE_INTEGER),
jsc.constant (-10000),
jsc.constant (-9999),
jsc.constant (-0.5),
jsc.constant (-0),
jsc.constant (0),
jsc.constant (0.5),
jsc.constant (9999),
jsc.constant (10000),
jsc.constant (Number.MAX_SAFE_INTEGER),
jsc.constant (Infinity)
);

// compose :: (b -> c) -> (a -> b) -> a -> c
const compose = f => g => x => f (g (x));

// empty :: Monoid m => m -> Boolean
const empty = m => Z.equals (m, Z.empty (m.constructor));

// not :: Boolean -> Boolean
const not = b => !b;

// testLaws :: Object -> Object -> Undefined
const testLaws = laws => arbs => {
(Object.keys (laws)).forEach (name => {
test (name.replace (/[A-Z]/g, c => ' ' + c.toLowerCase ()),
laws[name].apply (laws, arbs[name]));
});
};

// value :: { value :: a } -> a
const value = r => r.value;

Expand Down Expand Up @@ -61,10 +95,6 @@ test ('chain', () => {
eq (Z.chain (compose (Identity) (Math.sqrt), Identity (9))) (Identity (3));
});

test ('alt', () => {
eq (Z.alt (Identity ([1, 2]), Identity ([3, 4]))) (Identity ([1, 2, 3, 4]));
});

test ('reduce', () => {
eq (Z.reduce (Z.concat, [1, 2], Identity ([3, 4]))) ([1, 2, 3, 4]);
});
Expand All @@ -86,17 +116,161 @@ test ('@@show', () => {
eq (show (Identity ([1, 2, 3]))) ('Identity ([1, 2, 3])');
});

suite ('Comonad laws', () => {
suite ('Setoid laws', () => {
testLaws (laws.Setoid) ({
reflexivity: [
IdentityArb (NumberArb),
],
symmetry: [
IdentityArb (NumberArb),
IdentityArb (NumberArb),
],
transitivity: [
IdentityArb (NumberArb),
IdentityArb (NumberArb),
IdentityArb (NumberArb),
],
});
});

suite ('Ord laws', () => {
testLaws (laws.Ord) ({
totality: [
IdentityArb (NumberArb),
IdentityArb (NumberArb),
],
antisymmetry: [
IdentityArb (NumberArb),
IdentityArb (NumberArb),
IdentityArb (NumberArb),
],
transitivity: [
IdentityArb (NumberArb),
IdentityArb (NumberArb),
IdentityArb (NumberArb),
],
});
});

suite ('Semigroup laws', () => {
testLaws (laws.Semigroup (Z.equals)) ({
associativity: [
IdentityArb (jsc.string),
IdentityArb (jsc.string),
IdentityArb (jsc.string),
],
});
});

suite ('Functor laws', () => {
testLaws (laws.Functor (Z.equals)) ({
identity: [
IdentityArb (NumberArb),
],
composition: [
IdentityArb (NumberArb),
jsc.constant (Math.sqrt),
jsc.constant (Math.abs),
],
});
});

suite ('Apply laws', () => {
testLaws (laws.Apply (Z.equals)) ({
composition: [
IdentityArb (jsc.constant (Math.sqrt)),
IdentityArb (jsc.constant (Math.abs)),
IdentityArb (NumberArb),
],
});
});

suite ('Applicative laws', () => {
testLaws (laws.Applicative (Z.equals, Identity)) ({
identity: [
IdentityArb (NumberArb),
],
homomorphism: [
jsc.constant (Math.abs),
NumberArb,
],
interchange: [
IdentityArb (jsc.constant (Math.abs)),
NumberArb,
],
});
});

suite ('Chain laws', () => {
testLaws (laws.Chain (Z.equals)) ({
associativity: [
IdentityArb (jsc.asciistring),
jsc.constant (s => Identity (s.replace (/[A-Z]/g, ''))),
jsc.constant (s => Identity (s.toUpperCase ())),
],
});
});

test ('left identity',
(laws.Comonad (Z.equals)).leftIdentity (
IdentityArb (jsc.integer)
));
suite ('Monad laws', () => {
testLaws (laws.Monad (Z.equals, Identity)) ({
leftIdentity: [
jsc.constant (x => Identity ([x, x])),
IdentityArb (NumberArb),
],
rightIdentity: [
IdentityArb (NumberArb),
],
});
});

suite ('Foldable laws', () => {
testLaws (laws.Foldable (Z.equals)) ({
associativity: [
jsc.constant (Z.concat),
jsc.string,
IdentityArb (jsc.string),
],
});
});

test ('right identity',
(laws.Comonad (Z.equals)).rightIdentity (
IdentityArb (jsc.integer),
jsc.constant (identity => identity.value + 1)
));
suite ('Traversable laws', () => {
testLaws (laws.Traversable (Z.equals)) ({
naturality: [
jsc.constant (Array),
jsc.constant (Identity),
jsc.constant (xs => Identity (xs[0])),
IdentityArb (NonEmpty (jsc.array (NumberArb))),
],
identity: [
jsc.constant (Array),
IdentityArb (NumberArb),
],
composition: [
jsc.constant (Array),
jsc.constant (Identity),
IdentityArb (jsc.array (IdentityArb (NumberArb))),
],
});
});

suite ('Extend laws', () => {
testLaws (laws.Extend (Z.equals)) ({
associativity: [
IdentityArb (jsc.integer),
jsc.constant (identity => Z.extract (identity) + 1),
jsc.constant (identity => Math.pow (Z.extract (identity), 2)),
],
});
});

suite ('Comonad laws', () => {
testLaws (laws.Comonad (Z.equals)) ({
leftIdentity: [
IdentityArb (NumberArb),
],
rightIdentity: [
IdentityArb (NumberArb),
jsc.constant (identity => Math.pow (Z.extract (identity), 2)),
],
});
});

0 comments on commit 7a64a83

Please sign in to comment.