Skip to content

Instantly share code, notes, and snippets.

@svanellewee
Last active August 29, 2015 14:04
Show Gist options
  • Save svanellewee/e5383b6274976cbada71 to your computer and use it in GitHub Desktop.
Save svanellewee/e5383b6274976cbada71 to your computer and use it in GitHub Desktop.
Trying to understand Monads using javascript
// 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)))
@svanellewee
Copy link
Author

Remember!
Lambda in haskell : (\x -> ..do..something.. with..x)

@svanellewee
Copy link
Author

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