├── .gitignore ├── fantasy-identities.js ├── README.md ├── package.json ├── src └── identity.js └── test └── identity.js /.gitignore: -------------------------------------------------------------------------------- 1 | coverage 2 | node_modules 3 | -------------------------------------------------------------------------------- /fantasy-identities.js: -------------------------------------------------------------------------------- 1 | const Identity = require('./src/identity'); 2 | 3 | if (typeof module != 'undefined') 4 | module.exports = Identity; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fantasy Identities 2 | 3 | This project is no longer developed or maintained. 4 | Consider [sanctuary-identity][1] as a replacement. 5 | 6 | 7 | [1]: https://github.com/sanctuary-js/sanctuary-identity 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fantasy-identities", 3 | "version": "0.0.3", 4 | "description": "Identity data structure.", 5 | "repository": { 6 | "type": "git", 7 | "url": "git://github.com/fantasyland/fantasy-identities.git" 8 | }, 9 | "keywords": [ 10 | "fantasyland", 11 | "identity", 12 | "monad" 13 | ], 14 | "author": "Brian McKenna", 15 | "license": "MIT", 16 | "bugs": { 17 | "url": "https://github.com/fantasyland/fantasy-identities/issues" 18 | }, 19 | "dependencies": { 20 | "daggy": "0.0.x", 21 | "fantasy-combinators": "0.0.x" 22 | }, 23 | "devDependencies": { 24 | "nodeunit": "0.9.x", 25 | "fantasy-check": "0.1.4", 26 | "fantasy-helpers": "0.0.x", 27 | "fantasy-equality": "git+https://github.com/fantasyland/fantasy-equality.git" 28 | }, 29 | "scripts": { 30 | "readme": "$(npm bin)/emu < src/identity.js > README.md", 31 | "test": "node --harmony_destructuring node_modules/.bin/nodeunit test/*.js" 32 | }, 33 | "files": [ 34 | "fantasy-identities.js", 35 | "src/*.js" 36 | ], 37 | "main": "fantasy-identities.js" 38 | } 39 | -------------------------------------------------------------------------------- /src/identity.js: -------------------------------------------------------------------------------- 1 | const daggy = require('daggy'); 2 | const {identity} = require('fantasy-combinators'); 3 | 4 | const Identity = daggy.tagged('x'); 5 | 6 | // Methods 7 | Identity.of = Identity; 8 | Identity.prototype.chain = function(f) { 9 | return f(this.x); 10 | }; 11 | 12 | // Derived 13 | Identity.prototype.map = function(f) { 14 | return this.chain((a) => Identity.of(f(a))); 15 | }; 16 | Identity.prototype.ap = function(a) { 17 | return this.chain((f) => a.map(f)); 18 | }; 19 | 20 | Identity.prototype.sequence = function(p) { 21 | return this.traverse(identity, p); 22 | }; 23 | Identity.prototype.traverse = function(f, p) { 24 | return f(this.x).map(Identity.of); 25 | }; 26 | 27 | // Transformer 28 | Identity.IdentityT = (M) => { 29 | const IdentityT = daggy.tagged('run'); 30 | IdentityT.lift = IdentityT; 31 | IdentityT.of = (a) => IdentityT(M.of(a)); 32 | IdentityT.prototype.chain = function(f) { 33 | return IdentityT(this.run.chain((x) => f(x).run)); 34 | }; 35 | IdentityT.prototype.map = function(f) { 36 | return this.chain((a) => IdentityT.of(f(a))); 37 | }; 38 | IdentityT.prototype.ap = function(a) { 39 | return this.chain((f) => a.map(f)); 40 | }; 41 | return IdentityT; 42 | }; 43 | 44 | // Export 45 | if(typeof module != 'undefined') 46 | module.exports = Identity; 47 | -------------------------------------------------------------------------------- /test/identity.js: -------------------------------------------------------------------------------- 1 | const λ = require('fantasy-check/src/adapters/nodeunit'); 2 | const applicative = require('fantasy-check/src/laws/applicative'); 3 | const functor = require('fantasy-check/src/laws/functor'); 4 | const monad = require('fantasy-check/src/laws/monad'); 5 | 6 | const {isInstanceOf} = require('fantasy-helpers'); 7 | const {identity} = require('fantasy-combinators'); 8 | const {equals} = require('fantasy-equality'); 9 | 10 | const Identity = require('../fantasy-identities'); 11 | 12 | const isIdentity = isInstanceOf(Identity); 13 | const isIdentityOf = isInstanceOf(identityOf); 14 | 15 | function identityOf(type) { 16 | const self = this.getInstance(this, identityOf); 17 | self.type = type; 18 | return self; 19 | } 20 | 21 | function run(a) { 22 | return a.run; 23 | } 24 | 25 | const λʹ = λ 26 | .property('identityOf', identityOf) 27 | .method('arb', isIdentityOf, function(a, b) { 28 | return Identity.of(this.arb(a.type, b - 1)); 29 | }); 30 | 31 | exports.identity = { 32 | 33 | // Applicative Functor tests 34 | 'All (Applicative)': applicative.laws(λʹ)(Identity, identity), 35 | 'Identity (Applicative)': applicative.identity(λʹ)(Identity, identity), 36 | 'Composition (Applicative)': applicative.composition(λʹ)(Identity, identity), 37 | 'Homomorphism (Applicative)': applicative.homomorphism(λʹ)(Identity, identity), 38 | 'Interchange (Applicative)': applicative.interchange(λʹ)(Identity, identity), 39 | 40 | // Functor tests 41 | 'All (Functor)': functor.laws(λʹ)(Identity.of, identity), 42 | 'Identity (Functor)': functor.identity(λʹ)(Identity.of, identity), 43 | 'Composition (Functor)': functor.composition(λʹ)(Identity.of, identity), 44 | 45 | // Monad tests 46 | 'All (Monad)': monad.laws(λʹ)(Identity, identity), 47 | 'Left Identity (Monad)': monad.leftIdentity(λʹ)(Identity, identity), 48 | 'Right Identity (Monad)': monad.rightIdentity(λʹ)(Identity, identity), 49 | 'Associativity (Monad)': monad.associativity(λʹ)(Identity, identity), 50 | 51 | // Manual tests 52 | 'when testing traverse should return correct value': λʹ.check( 53 | (a) => { 54 | return equals(a.traverse(identity, Identity), a); 55 | }, 56 | [λʹ.identityOf(λʹ.identityOf(Number))] 57 | ), 58 | 'when testing sequence should return correct type': λʹ.check( 59 | (a) => { 60 | return isIdentity(a.sequence()); 61 | }, 62 | [λʹ.identityOf(λʹ.identityOf(Number))] 63 | ), 64 | 'when testing sequence should return correct nested type': λʹ.check( 65 | (a) => { 66 | return isIdentity(a.sequence().x); 67 | }, 68 | [λʹ.identityOf(λʹ.identityOf(Number))] 69 | ), 70 | 'when testing sequence should return correct value': λʹ.check( 71 | (a) => { 72 | return a.sequence().x.x === a.x.x; 73 | }, 74 | [λʹ.identityOf(λʹ.identityOf(Number))] 75 | ) 76 | }; 77 | 78 | exports.identityT = { 79 | 80 | // Applicative Functor tests 81 | 'All (Applicative)': applicative.laws(λʹ)(Identity.IdentityT(Identity), run), 82 | 'Identity (Applicative)': applicative.identity(λʹ)(Identity.IdentityT(Identity), run), 83 | 'Composition (Applicative)': applicative.composition(λʹ)(Identity.IdentityT(Identity), run), 84 | 'Homomorphism (Applicative)': applicative.homomorphism(λʹ)(Identity.IdentityT(Identity), run), 85 | 'Interchange (Applicative)': applicative.interchange(λʹ)(Identity.IdentityT(Identity), run), 86 | 87 | // Functor tests 88 | 'All (Functor)': functor.laws(λʹ)(Identity.IdentityT(Identity).of, run), 89 | 'Identity (Functor)': functor.identity(λʹ)(Identity.IdentityT(Identity).of, run), 90 | 'Composition (Functor)': functor.composition(λʹ)(Identity.IdentityT(Identity).of, run), 91 | 92 | // Monad tests 93 | 'All (Monad)': monad.laws(λʹ)(Identity.IdentityT(Identity), run), 94 | 'Left Identity (Monad)': monad.leftIdentity(λʹ)(Identity.IdentityT(Identity), run), 95 | 'Right Identity (Monad)': monad.rightIdentity(λʹ)(Identity.IdentityT(Identity), run), 96 | 'Associativity (Monad)': monad.associativity(λʹ)(Identity.IdentityT(Identity), run) 97 | }; 98 | --------------------------------------------------------------------------------