Created
March 6, 2014 04:23
-
-
Save RocketPuppy/9382640 to your computer and use it in GitHub Desktop.
This file contains 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 Maybe monad type. All monads must respond to both `bind` and `return` | |
* functions. Here return is called `ret` as return is already a keyword. I've | |
* defined `bind` and `return` on the Maybe prototype so they can be used by | |
* the two subclasses `Just` and `Nothing`. | |
*/ | |
function Maybe(){} | |
/* | |
* The bind function takes a single function as an argument. That function must | |
* take a value of the same type as is inside the Just and return a new | |
* instance of the Maybe class (either Just or Nothing). | |
* If bind is called on a Just, it applies the given function to the value in | |
* the just. | |
* If bind is called on a Nothing, it short circuits and returns Nothing. | |
*/ | |
Maybe.prototype.bind = function(f){ | |
if(this instanceof Just){ | |
return f(this.val); | |
} | |
else if(this instanceof Nothing){ | |
return Maybe.Nothing; | |
} | |
}; | |
/* | |
* The ret(urn) function simply wraps a value in the default context of the | |
* monad. In this case, a Just. | |
*/ | |
Maybe.prototype.ret = function(val){ | |
return new Just(val); | |
}; | |
/* | |
* For something to be a monad it must have more than just the bind and return | |
* functions. Those functions also need to abide by the monad laws. Here I'll | |
* prove that these do just that. | |
* | |
* First: Left-identity - (return x).bind(f) === f x | |
* 1. (Maybe.ret(x)).bind(f) === f x | |
* 2. (Just(x)).bind(f) === f x //Maybe.ret(x) simplifies to Just(x) | |
* 3. f x === f x //Just(x).bind(f) simplifies to f x | |
* | |
* Second: Right-identity - m.bind(return) === m | |
* Case 1: Nothing | |
* 1. Nothing.bind(Maybe.ret) === Nothing | |
* 2. Nothing === Nothing //Nothing.bind(Maybe.ret) simplifies to Nothing | |
* Case 2: Just(x) | |
* 1. (new Just(x)).bind(Maybe.ret) === Just(x) | |
* 2. Maybe.ret(x) === Just(x) //bind applies Maybe.ret to the inner value | |
* 3. Just(x) === Just(x) //Maybe.ret returns a new Just with the given value | |
* | |
* Third: Associativity - (m.bind(f)).bind(g) === m.bind( function(x){ f(x).bind(g) } ) | |
* Case 1: Nothing | |
* 1. (Nothing.bind(f)).bind(g) === Nothing.bind( function(x){ f(x).bind(g) } ) | |
* 2. Nothing.bind(g) === Nothing //the first binds simplify to Nothing | |
* 3. Nothing === Nothing //the last bind simplifies to Nothing | |
* Case 2: Just(y) | |
* 1. (Just(y).bind(f)).bind(g) === (Just(y)).bind( function(x){ f(x).bind(g) } ) | |
* 2. (f(y)).bind(g) === (function(y){ f(y).bind(g) })(y) //the first binds simplify | |
* 3. f(y).bind(g) === f(y).bind(g) //reduce function and parens | |
*/ | |
/* | |
* The Just subclass of Maybe. It contains a single value. | |
*/ | |
function Just(val){ | |
this.val = val; | |
} | |
Just.prototype = new Maybe(); | |
/* | |
* The Nothing subclass of Maybe. It signifies Nothing. | |
*/ | |
function Nothing(){} | |
Nothing.prototype = new Maybe(); | |
Maybe.Nothing = new Nothing(); | |
/* | |
* A possible use of the Maybe monad. | |
* Here we have a safe division operation. Used with bind, it will return | |
* Nothing if its argument is 0, short-circuiting the rest of the chain and | |
* preventing an exception. | |
*/ | |
function safeDiv(num){ | |
return function(denom){ | |
if(denom != 0){ | |
return new Just(num/denom); | |
} | |
else{ | |
return Maybe.Nothing | |
} | |
} | |
} | |
/* | |
* Usage Examples | |
*/ | |
onlyEven = function(x){ | |
if(x % 2 === 0){ | |
return new Just(x); | |
} | |
else{ | |
return Maybe.Nothing; | |
} | |
}; | |
onlyOdd = function(x){ | |
if(x % 2 === 0){ | |
return Maybe.Nothing; | |
} | |
else{ | |
return new Just(x); | |
} | |
}; | |
usage1 = function(x){return (new Just(x)).bind(function(x){ return new Just(x + 20)}).bind(function(x) {return new Just(x * 4)}).bind(safeDiv(62345)).bind(function(x){ return new Just(x - 4)})} | |
/* | |
* There exists a concept called "Lifting" which allows one to convert a | |
* function that isn't in a monad, to one that is. I'm not sure how to | |
* implement that in JS right now. | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment