Last active
August 29, 2015 14:04
-
-
Save svanellewee/e5383b6274976cbada71 to your computer and use it in GitHub Desktop.
Trying to understand Monads using javascript
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
// borrowed from https://blog.jcoglan.com/2011/03/11/promises-are-the-monad-of-asynchronous-programming/ | |
// also http://blog.jcoglan.com/2011/03/05/translation-from-haskell-to-javascript-of-selected-portions-of-the-best-introduction-to-monads-ive-ever-read/ | |
// and http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html | |
var pp = console.log | |
var f = function(x) { return x*3 } // a "Float" value | |
var g = function(x) { return x+10 } // a "Float" value | |
// http://en.wikipedia.org/wiki/Monad_(functional_programming)#Formal_definition | |
// turns monad type from type | |
// t -> M t (point 2) | |
// Float -> (Float, String) | |
var unit = function (x) { | |
return [ x, "" ] // --> kinda like the "type constructor" (point1) | |
} | |
var compose = function () { | |
var functions = arguments | |
return function(x) { | |
return Array.prototype.reduceRight.call(functions, function( total, cur_fun ) { | |
return cur_fun(total) | |
}, x); | |
} | |
}; | |
var pipe = function(x, functions) { | |
return Array.prototype.reduce.call(functions, function( total, cur_fun ) { | |
return cur_fun(total) | |
}, x); | |
}; | |
pp(pipe ( 3, [f, g])) | |
var lift = function(fn) { return compose(unit, fn) } | |
// bind :: (Float -> (Float,String)) -> ((Float,String) -> (Float,String)) | |
// in other words bind takes function (Float-> (Float,String)) and returns ANOTHER FUNCTION ((Float,String) -> (Float,String)) | |
// fn :: Float -> (Float, String) | |
// bind fn :: (Float, String) -> (Float, String) | |
var bind = function(fn) { | |
// bind fn :: (Float, String) -> (Float, String) | |
var bind_fn = function(gtuple) { | |
var gresult = gtuple[0]; | |
var gstring = gtuple[1]; // gstring I know I know. | |
var ftuple = fn(gresult); | |
var fresult = ftuple[0]; | |
var fstring = ftuple[1]; | |
return [fresult, gstring + fstring ]; | |
} | |
return bind_fn | |
} | |
var pipe2 = function(x, functions) { | |
return Array.prototype.reduce.call(functions, function( total, cur_fun ) { | |
return bind(cur_fun)(total) | |
}, x); | |
}; | |
pp(pipe ( unit(3), [bind(lift(f)), bind(lift(g))])) | |
var z = pipe(unit(7), [ bind(function(x) { return [x+1, 'inc.'] }), | |
bind(function(x) { return [2*x, 'double.'] }), | |
bind(function(x) { return [x-1, 'dec.'] }) | |
]) | |
pp(z) | |
var z = pipe2(unit(7), [ function(x) { return [x+1, 'inc.'] }, | |
function(x) { return [2*x, 'double.'] }, | |
function(x) { return [x-1, 'dec2.'] } | |
]) | |
pp(z) | |
//Laws: | |
// return == unit | |
// m >>= return | |
pp(">>", bind(unit)(unit( 12) )) | |
// must be same as m | |
pp(">>", unit(12)) | |
// return law: | |
// must be the same: | |
pp(bind(lift(f))(unit(12))) // (return x) >>= f | |
pp(lift(f)(12)) // f x | |
// Binding two functions in succession is the same as binding one function that can be determined from them: | |
//(m >>= f) >>= g | |
pp(bind(lift(g))(bind(lift(f))(unit(12)))) | |
// m >>= ( \x -> (f x >>= g)) | |
pp(bind(function(x) { | |
return bind(lift(g))(lift(f)(x)) | |
})(unit(12))) | |
So far it seems bind (">>=") has a job of turning the function into another function that takes a monadic type and returns the same type... Or maybe I'm wrong?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Remember!
Lambda in haskell : (\x -> ..do..something.. with..x)