As I learn about monads after reading dozens of tutorials I'm trying to implement the pattern in JavaScript. I'm using LiveScript and Prelude to translate some Haskell monad examples.
So the monad I'm trying to implement as an exercise is the List monad. I wrote the following, in LiveScript:
List = do ->
# unit :: a -> ma
unit = (a) -> [a]
# bind :: ma -> (a -> mb) -> mb
bind = (ma, f) --> concat (map f) ma
# lift :: (a -> b) -> ma -> mb
lift = (f, ma) --> bind ma, (a) -> unit f a
{unit, bind, lift}
add1 = (x) -> x+1
let {unit, bind} = List
x <- bind [1]
y <- bind [2]
z <- bind [3]
unit add1 x+y+z #=> [7]
(List.lift add1) [1 2 3] #=> [2 3 4]
The LiveScript syntax to nest functions at the same level of indentation is quite handy, but it translates to a JavaScript callback hell obviously:
List = function(){
var unit, bind, lift;
unit = function(a){
return [a];
};
bind = curry$(function(ma, f){
return concat(map(f)(ma));
});
lift = curry$(function(f, ma){
return bind(ma, function(a){
return unit(f(a));
});
});
return { unit: unit, bind: bind, lift: lift };
}();
add1 = function(x){
return x + 1;
};
(function(arg$){
var unit, bind;
unit = arg$.unit, bind = arg$.bind;
bind([1], function(x){
return bind([2], function(y){
return bind([3], function(z){
return unit(add1(x + y + z));
});
});
});
}.call(this, List));
List.lift(add1)([1, 2, 3]);
What I want is to implement the pattern on the receiver to be able to use it like so:
List([1]).bind([2]).bind([3]).do(function(x,y,z){ x+y+z });
After watching this video where Crockford explains monads in JavaScript (code), I understand that the MONAD
he presents is just an object with methods that could be also be implemented with prototypes. The unit
method is the constructor and bind
is an instance method that runs a function on the value with the given arguments. Then lift
adds a new method to the prototype that runs the given function on the monadic value.
But, is it an actual monad or a monadic pattern like jQuery? I have doubts about this particular explanation of monads because there is no computation sequence, the bind
method runs the function right away and returns a new instance of the "monad", it is not composition, as in the monad I implemented in LiveScript which was based on the Haskell examples.
So my question is:
- Is my implementation of monad correct?
- Is Crockford's implementation of monad correct?