memo: monad in javascript
(function(){ //unit: a -> M[b] var unit = function(value){ return { value : function(){return value} }; }; //bind: M[a] -> (a->M[b]) -> M[b] var bind = function(m,proc){ return proc( m.value() ); }; // func a->M[b] var x2 = function(x){return unit(x*x)}; var inc = function(x){return unit(x+1)}; //return a >>= f ≡ f a print( bind( unit(10) , x2 ).value(), x2(10).value()); //m >>= return ≡ m print( bind( unit(10) , unit ).value(),unit(10).value()); //(m >>= f) >>= g ≡ m >>= (\x -> f x >>= g) print( bind( bind( unit(10) , x2 ) ,inc ).value(), bind( unit(10) , function(x){ return bind( x2(x) ,inc)}).value() ); })();
評価とか型とかないからあれだけど、
一番単純な形だとこんな雰囲気になるはず。
これだとなんの役にも立たないので、構造を覚えていて
valueが呼ばれるまで評価しないmonadを作ってみる。
(function(){ //unit: a -> M[b] var unit = function(value){ var ret = (value.call) ? value : (value.value) ? value.value : function(){return value} return { value : ret }; }; //bind: M[a] -> (a->M[b]) -> M[b] var bind = function(m,proc){ return unit(function(){ return proc( m.value() ).value() }); }; // bindが逐次実行じゃなくて評価前の状態を保存する // ように作る。 // func a->M[b] var x2 = function(x){return unit(x*x)}; var inc = function(x){return unit(x+1)}; print( unit(10).value()); print( unit(unit(10)).value()) print( bind(unit(10),x2).value()); print( bind( bind(unit(10),x2),inc).value()); //return a >>= f 竕。 f a print( bind( unit(10) , x2 ).value(), x2(10).value()); //m >>= return 竕。 m print( bind( unit(10) , unit ).value(),unit(10).value()); //(m >>= f) >>= g 竕。 m >>= (\x -> f x >>= g) print( bind( bind( unit(10) , x2 ) ,inc ).value(), bind( unit(10) , function(x){ return bind( x2(x) ,inc)}).value() ); var process = [inc,inc,x2,x2,inc]; var m = unit(1); process.forEach(function(e){ m = bind( m , e ); }); print("before evaluate"); print(m.value()); print("afater evaluate") })();
Array.prototype.flatMapを実装するとArrayもmonadに。
Array.prototype.flatMap = function(f){ var ret = []; this.forEach(function(e){ ret = ret.concat( f(e) ); }); return ret; }; //unit: a -> M[b] var unit = function(value){ return [value]; }; //bind: M[a] -> (a->M[b]) -> M[b] var bind = function(m,proc){ return m.flatMap(proc); }; // func a->M[b] var x2 = function(e){return unit(e*e)}; var inc = function(e){return unit(e+1)}; //return a >>= f == f a print( bind( unit(10) , x2 ), x2(10)); print( [10].flatMap(x2),x2(10)); //m >>= return == m print( bind( unit(10) , unit ),unit(10)); print( [10].flatMap(function(e){return [e]}), [10]); //(m >>= f) >>= g == m >>= (\x -> f x >>= g) print( bind( bind( unit(10,1) , x2 ) ,inc ), bind( unit(10,1) , function(x){ return bind( x2(x) ,inc)}) ); print( [10].flatMap(x2).flatMap(inc), [10].flatMap(function(x){ return x2(x).flatMap(inc)}) );