Last active
September 28, 2019 16:09
-
-
Save dypsilon/437b84fd31b255b7ef2e47ceaa91245a to your computer and use it in GitHub Desktop.
A simple implementation of the identity monad without any dependencies. Including testing the algebraic laws.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * The Identity monad is a monad that does not embody any computational strategy. | |
| * It simply applies the bound function to its input without any modification. | |
| * Computationally, there is no reason to use the Identity monad instead of the much simpler | |
| * act of simply applying functions to their arguments. | |
| * | |
| * The purpose of the Identity monad is its fundamental role in the theory of monad transformers. | |
| * Any monad transformer applied to the Identity monad yields a non-transformer version of that monad. | |
| * | |
| * source: https://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Identity.html | |
| */ | |
| class Identity { | |
| constructor(x) { | |
| this.x = x; | |
| } | |
| } | |
| Identity.prototype.of = Identity.of = x => new Identity(x) | |
| Identity.prototype.chain = function(f) { | |
| return f(this.x); | |
| }; | |
| Identity.prototype.map = function(f) { | |
| return this.of(f(this.x)); | |
| } | |
| Identity.prototype.ap = function(m) { | |
| return m.map(this.x); | |
| } | |
| Identity.prototype.inspect = function() { | |
| return `Identity(${this.x})`; | |
| } | |
| Identity.prototype.equals = function(expected) { | |
| return expected instanceof Identity && this.x === expected.x; | |
| } | |
| module.exports = Identity; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * These are some very simple tests. | |
| * You can find extensive law testing library here: https://github.com/ramda/ramda-fantasy/blob/master/test/types.js | |
| * It has many dependencies, though. | |
| */ | |
| const Identity = require('./identity'); | |
| const eq = (test, expected, actual) => { | |
| if(!expected.equals(actual)) { | |
| throw new Error(`Test failed: ${ test }`); | |
| } | |
| }; | |
| { // Functor | |
| const u = Identity.of(1); | |
| const f = (x) => x + 1; | |
| const g = (x) => x + 2; | |
| eq('Functor: identity', u.map(x => x), u); | |
| eq('Functor: composition', u.map(x => f(g(x))), u.map(g).map(f)); | |
| } | |
| { // Apply | |
| const a = Identity.of((x) => x + 1); | |
| const u = Identity.of((x) => x + 2); | |
| const v = Identity.of(1); | |
| eq( | |
| 'Apply: composition', | |
| a.map(f => g => x => f(g(x))).ap(u).ap(v), | |
| a.ap(u.ap(v)) | |
| ) | |
| } | |
| { // Applicative | |
| const a = Identity; | |
| const v = Identity.of(1); | |
| const f = x => x + 1; | |
| const u = Identity.of(x => x + 2) | |
| const x = 2; | |
| const y = 4; | |
| eq('Applicative: identity', a.of(x => x).ap(v), v); | |
| eq('Applicative: homomorphism', a.of(f).ap(a.of(x)), a.of(f(x))); | |
| eq('Applicative: interchange', u.ap(a.of(y)), a.of((f) => f(y)).ap(u)); | |
| } | |
| { // Chain | |
| const m = Identity.of(3); | |
| const f = x => Identity.of(x + 1); | |
| const g = x => Identity.of(x + 2); | |
| eq('Chain: associativity', m.chain(f).chain(g), m.chain(x => f(x).chain(g))); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment