From 5a0c706936c1d36ff22db7922f657f715286c00b Mon Sep 17 00:00:00 2001 From: Christoph Hermann Date: Sat, 20 Feb 2016 11:42:00 +0100 Subject: [PATCH] adds `Ord` --- README.md | 4 ++-- fantasy-monoids.js | 10 ++++++++-- package.json | 12 ++++++++---- src/concat.js | 3 +++ src/max.js | 21 +++++++++++++-------- src/mconcat.js | 5 +++++ src/min.js | 21 +++++++++++++-------- src/ord.js | 38 ++++++++++++++++++++++++++++++++++++++ test/max.js | 44 +++++++++++++++++++++++++++++++++++++------- test/min.js | 44 +++++++++++++++++++++++++++++++++++++------- test/ord.js | 21 +++++++++++++++++++++ 11 files changed, 185 insertions(+), 38 deletions(-) create mode 100644 src/concat.js create mode 100644 src/mconcat.js create mode 100644 src/ord.js create mode 100644 test/ord.js diff --git a/README.md b/README.md index 27305fc..a1d9de6 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,8 @@ | Endo | function identity | function composition | | Multiplicative | 1 | * | | Unit | {} | {} | -| Min | Number.MAX_VALUE | < | -| Max | Number.MIN_VALUE | > | +| Min(Ord) | Ord.min | Ord.compare | +| Max(Ord) | Ord.max | Ord.compare | ## Testing diff --git a/fantasy-monoids.js b/fantasy-monoids.js index 8d749dd..0500f63 100644 --- a/fantasy-monoids.js +++ b/fantasy-monoids.js @@ -7,8 +7,11 @@ const Dual = require('./src/dual'); const Endo = require('./src/endo'); const Multiplicative = require('./src/multiplicative'); const Unit = require('./src/unit'); -const Min = require('./src/min'); -const Max = require('./src/max'); +const Ord = require('./src/ord'); +const Min = require('./src/min'); +const Max = require('./src/max'); +const concat = require('./src/concat'); +const mconcat = require('./src/mconcat'); module.exports = { Additive , Conjunction @@ -19,4 +22,7 @@ module.exports = { Additive , Unit , Min , Max + , Ord + , concat + , mconcat }; diff --git a/package.json b/package.json index 3b1d9ef..f08c54e 100644 --- a/package.json +++ b/package.json @@ -21,14 +21,18 @@ "fantasy-combinators": "git+https://github.com/fantasyland/fantasy-combinators.git" }, "devDependencies": { - "nodeunit": "0.9.x", "fantasy-check": "git+https://github.com/fantasyland/fantasy-check.git", - "fantasy-identities": "git+https://github.com/fantasyland/fantasy-identities.git" + "fantasy-identities": "git+https://github.com/fantasyland/fantasy-identities.git", + "mocha": "^2.4.5", + "nodeunit": "0.9.x" }, "scripts": { - "test": "node --harmony_destructuring node_modules/.bin/nodeunit test/*.js" + "test": "node --harmony_destructuring node_modules/.bin/nodeunit test/*.js" }, - "files": ["fantasy-monoids.js", "src/*.js"], + "files": [ + "fantasy-monoids.js", + "src/*.js" + ], "main": "fantasy-monoids.js", "version": "0.0.1" } diff --git a/src/concat.js b/src/concat.js new file mode 100644 index 0000000..e147ebf --- /dev/null +++ b/src/concat.js @@ -0,0 +1,3 @@ +const concat = (x, y) => x.concat(y); + +module.exports = concat; diff --git a/src/max.js b/src/max.js index eee0b01..318e140 100644 --- a/src/max.js +++ b/src/max.js @@ -2,17 +2,22 @@ const {tagged} = require('daggy'); const {empty, of, concat, equals} = require('fantasy-land'); +const {compare, min, GT} = require('./ord'); -const Max = tagged('x'); +const Max = Ord => { + const Max = tagged('x'); -Max[of] = x => Max(x); -Max[empty] = () => Max(Number.MIN_VALUE); + Max[of] = x => Max(Ord[of](x)); + Max[empty] = () => Max(Ord[min]()); -Max.prototype[equals] = function(y) { - return this.x === y.x; -}; -Max.prototype[concat] = function(y) { - return Max(this.x > y.x ? this.x : y.x); + Max.prototype[equals] = function(y) { + return this.x[equals](y.x); + }; + Max.prototype[concat] = function(y) { + return Max(this.x[compare](y.x) === GT ? this.x: y.x); + }; + + return Max; }; module.exports = Max; diff --git a/src/mconcat.js b/src/mconcat.js new file mode 100644 index 0000000..79d6bbf --- /dev/null +++ b/src/mconcat.js @@ -0,0 +1,5 @@ +const concat = require('./concat'); + +const mconcat = (xs, empty) => xs.length ? xs.reduce(concat) : empty(); + +module.exports = mconcat; diff --git a/src/min.js b/src/min.js index ce03e7f..d2ac656 100644 --- a/src/min.js +++ b/src/min.js @@ -2,17 +2,22 @@ const {tagged} = require('daggy'); const {empty, of, concat, equals} = require('fantasy-land'); +const {compare, max, LT} = require('./ord'); -const Min = tagged('x'); +const Min = Ord => { + const Min = tagged('x'); -Min[of] = x => Min(x); -Min[empty] = () => Min(Number.MAX_VALUE); + Min[of] = x => Min(Ord[of](x)); + Min[empty] = () => Min(Ord[max]()); -Min.prototype[equals] = function(y) { - return this.x === y.x; -}; -Min.prototype[concat] = function(y) { - return Min(this.x < y.x ? this.x : y.x); + Min.prototype[equals] = function(y) { + return this.x[equals](y.x); + }; + Min.prototype[concat] = function(y) { + return Min(this.x[compare](y.x) === LT ? this.x : y.x); + }; + + return Min; }; module.exports = Min; diff --git a/src/ord.js b/src/ord.js new file mode 100644 index 0000000..0632900 --- /dev/null +++ b/src/ord.js @@ -0,0 +1,38 @@ +'use strict'; + +const {tagged} = require('daggy'); +const {empty, of, concat, equals} = require('fantasy-land'); + +const Ord = M => { + + const _Ord = tagged('x'); + + _Ord[of] = _Ord; + _Ord[Ord.min] = M[Ord.min]; + _Ord[Ord.max] = M[Ord.max]; + + _Ord.prototype.compare = function(y) { + return M.compare(this.x, y.x); + }; + _Ord.prototype[equals] = function(y) { + return M.compare(this.x, y.x) === Ord.EQ; + }; + _Ord.prototype.lt = function(y) { + return M.compare(this.x, y.x) === Ord.LT; + }; + _Ord.prototype.gt = function(y) { + return M.compare(this.x, y.x) === Ord.GT; + }; + + return _Ord; +}; + +Ord.EQ = 0; +Ord.GT = 1; +Ord.LT = -1; + +Ord.compare = 'compare'; +Ord.min = 'min'; +Ord.max = 'max'; + +module.exports = Ord; diff --git a/test/max.js b/test/max.js index 0ba84e4..dd9ad6b 100644 --- a/test/max.js +++ b/test/max.js @@ -7,24 +7,54 @@ const m = require('fantasy-land/laws/monoid'); const s = require('fantasy-land/laws/semigroup'); const sʹ = require('fantasy-land/laws/setoid'); -const {Max} = require('../fantasy-monoids'); +const {Max, Ord, mconcat} = require('../fantasy-monoids'); +const Ordʹ = Ord({ min: () => Ordʹ(Number.MIN_NUMBER) + , max: () => Ordʹ(Number.MAX_NUMBER) + , compare: (x, y) => x === y ? Ord.EQ : x < y ? Ord.LT : Ord.GT + }); +const Maxʹ = Max(Ordʹ); exports.monoid = { - 'rightIdentity': λ.law(m.rightIdentity)(Max), - 'leftIdentity': λ.law(m.leftIdentity)(Max) + 'rightIdentity': λ.law(m.rightIdentity)(Maxʹ), + 'leftIdentity': λ.law(m.leftIdentity)(Maxʹ) }; exports.semigroup = { - 'associativity': λ.law(s.associativity)(Max) + 'associativity': λ.law(s.associativity)(Maxʹ.of) }; exports.setoid = { - 'reflexivity': λ.law(sʹ.reflexivity)(Max), - 'symmetry': λ.law(sʹ.symmetry)(Max), - 'transitivity': λ.law(sʹ.transitivity)(Max) + 'reflexivity': λ.law(sʹ.reflexivity)(Maxʹ.of), + 'symmetry': λ.law(sʹ.symmetry)(Maxʹ.of), + 'transitivity': λ.law(sʹ.transitivity)(Maxʹ.of) +}; + +exports.basicUsage = test => { + const expected = { x: { x: 9 } }; + + test.deepEqual( + Maxʹ(Ordʹ(3)) + .concat(Maxʹ(Ordʹ(6))) + .concat(Maxʹ(Ordʹ(8))) + .concat(Maxʹ(Ordʹ(9))) + .concat(Maxʹ(Ordʹ(1))) + , expected + ) + test.deepEqual( + mconcat([ Maxʹ(Ordʹ(3)) + , Maxʹ(Ordʹ(6)) + , Maxʹ(Ordʹ(8)) + , Maxʹ(Ordʹ(9)) + , Maxʹ(Ordʹ(1)) + ], Maxʹ.empty() + ) + , expected); + + + test.done(); }; diff --git a/test/min.js b/test/min.js index 60f791d..763351a 100644 --- a/test/min.js +++ b/test/min.js @@ -7,24 +7,54 @@ const m = require('fantasy-land/laws/monoid'); const s = require('fantasy-land/laws/semigroup'); const sʹ = require('fantasy-land/laws/setoid'); -const {Min} = require('../fantasy-monoids'); +const {Min, Ord, mconcat} = require('../fantasy-monoids'); +const Ordʹ = Ord({ min: () => Ordʹ(Number.MIN_NUMBER) + , max: () => Ordʹ(Number.MAX_NUMBER) + , compare: (x, y) => x === y ? Ord.EQ : x < y ? Ord.LT : Ord.GT + }); +const Minʹ = Min(Ordʹ); exports.monoid = { - 'rightIdentity': λ.law(m.rightIdentity)(Min), - 'leftIdentity': λ.law(m.leftIdentity)(Min) + 'rightIdentity': λ.law(m.rightIdentity)(Minʹ), + 'leftIdentity': λ.law(m.leftIdentity)(Minʹ) }; exports.semigroup = { - 'associativity': λ.law(s.associativity)(Min) + 'associativity': λ.law(s.associativity)(Minʹ.of) }; exports.setoid = { - 'reflexivity': λ.law(sʹ.reflexivity)(Min), - 'symmetry': λ.law(sʹ.symmetry)(Min), - 'transitivity': λ.law(sʹ.transitivity)(Min) + 'reflexivity': λ.law(sʹ.reflexivity)(Minʹ.of), + 'symmetry': λ.law(sʹ.symmetry)(Minʹ.of), + 'transitivity': λ.law(sʹ.transitivity)(Minʹ.of) +}; + +exports.basicUsage = test => { + const expected = { x: { x: 1 } }; + + test.deepEqual( + Minʹ(Ordʹ(3)) + .concat(Minʹ(Ordʹ(6))) + .concat(Minʹ(Ordʹ(8))) + .concat(Minʹ(Ordʹ(9))) + .concat(Minʹ(Ordʹ(1))) + , expected + ) + test.deepEqual( + mconcat([ Minʹ(Ordʹ(3)) + , Minʹ(Ordʹ(6)) + , Minʹ(Ordʹ(8)) + , Minʹ(Ordʹ(9)) + , Minʹ(Ordʹ(1)) + ], Minʹ.empty() + ) + , expected); + + + test.done(); }; diff --git a/test/ord.js b/test/ord.js new file mode 100644 index 0000000..58c63d3 --- /dev/null +++ b/test/ord.js @@ -0,0 +1,21 @@ +'use strict'; + +const {adapters: {nodeunit: λ}} = require('fantasy-check'); +const {identity} = require('fantasy-combinators'); + +const sʹ = require('fantasy-land/laws/setoid'); + +const {Ord} = require('../fantasy-monoids'); + +const Ordʹ = Ord({ min: () => undefined + , max: () => undefined + , compare: (x, y) => x === y ? Ord.EQ: x < y ? Ord.LT: Ord.GT + }); + + +exports.setoid = { + + 'reflexivity': λ.law(sʹ.reflexivity)(Ordʹ.of), + 'symmetry': λ.law(sʹ.symmetry)(Ordʹ.of), + 'transitivity': λ.law(sʹ.transitivity)(Ordʹ.of) +};