|
var Y = function(f) { |
|
return |
|
(function (x) { return f(function (v) { return x(x)(v); }); }) |
|
(function (x) { return f(function (v) { return x(x)(v); }); }); |
|
} |
|
|
|
var dot = function(f, g) { |
|
return function(x) { |
|
return f(g(x)); |
|
}; |
|
}; |
|
|
|
var thunkEval = function(z) { |
|
while (z.constructor === Array) z = z[0].apply(null, z.slice(1)); |
|
return z; |
|
}; |
|
|
|
var foldl = function(f, z0, xs0) { |
|
var go = function(z, xs) { |
|
if (xs.length === 0) return z; |
|
return [go, f(z, xs[0]), xs.slice(1)]; |
|
} |
|
return thunkEval(go(z0, xs0)); |
|
}; |
|
|
|
var papply = function(f) { |
|
var args = [].slice.call(arguments, 1); |
|
return function() { |
|
return f.apply(this, args.concat([].slice.call(arguments))); |
|
}; |
|
}; |
|
|
|
var cofoldl = function(f, z0) { |
|
var go = function(z1) { |
|
var z2 = f(z0, z1); |
|
return cofoldl(f, z2); |
|
}; |
|
return [z0, go]; |
|
}; |
|
|
|
var cohelper = function(q) { |
|
return function(x1) { |
|
return (arguments.length === 0) ? |
|
q[0] : cohelper(q[1]([].slice.call(arguments))); |
|
}; |
|
}; |
|
|
|
|
|
var foldM = function(f, a, as) { |
|
if (as.length === 0) return a; |
|
return List.bind(f(a, as[0]), function(fax) { |
|
return foldM(f, fax, as.slice(1)); |
|
}); |
|
}; |
|
|
|
var add = function(a, b) { return a + b; }; |
|
|
|
var sum = papply(foldl, add, 0); |
|
|
|
var shift = function(o) { |
|
for (var k in o) return [k, o[k]]; |
|
}; |
|
|
|
var Monad = function(m, defs) { |
|
for (var k in defs) { |
|
m[k] = defs[k]; |
|
} |
|
|
|
var ctx = {}; // TODO Totally the wrong place for this. |
|
|
|
var prepare = function(args) { |
|
args = args.constructor === Array ? args : [args]; |
|
if (args[0].constructor === Object) { |
|
var _ = shift(args[0]), name = _[0], func = _[1]; |
|
func = defs.bind(func, function(x) { |
|
ctx[name] = x; |
|
return defs.return_(); |
|
}); |
|
args[0] = func; |
|
} |
|
var sargs = args.slice(1); |
|
for (var i = 0; i < sargs.length; i++) { |
|
if (sargs[i] in ctx) { |
|
sargs[i] = ctx[sargs[i]]; |
|
} |
|
} |
|
return sargs.length === 0 ? args[0] : args[0].apply(null, sargs); |
|
}; |
|
|
|
m.do_ = function(x) { |
|
return cohelper(cofoldl(function(m0, m1) { |
|
return defs.bind(prepare(m0), function(_) { return prepare(m1); }); |
|
}, x)); |
|
}; |
|
|
|
m.liftM = function(f) { |
|
return function(m) { |
|
return defs.bind(m, function(x) { |
|
return defs.return(f(x)); |
|
}); |
|
}; |
|
}; |
|
}; |
|
|
|
var Cont = function() {}; |
|
Monad(Cont, { |
|
bind: function(m, f) { |
|
return function(k) { |
|
return m(function(x) { |
|
// TODO trampoline |
|
setTimeout(function() { |
|
var next = f(x); |
|
if (next) next(k); |
|
}, 0); |
|
}); |
|
}; |
|
}, |
|
return_: function(x) { |
|
return function(k) { |
|
return k(x); |
|
}; |
|
} |
|
}); |
|
|
|
var forever = function(p, m) { |
|
var m_ = Cont.bind(m, function(_) { return m_; }); |
|
return m_; |
|
}; |
|
|
|
var List = function() {}; |
|
Monad(List, { |
|
bind: function(m, f) { |
|
var xs = []; |
|
for (var i = 0; i < m.length; i++) { |
|
xs = xs.concat(f(m[i])); |
|
} |
|
return xs; |
|
}, |
|
return_: function(x) { return [x]; }, |
|
mplus: function(a, b) { return a.concat(b); }, |
|
mzero: [] |
|
}); |
|
|
|
if (typeof exports === "undefined") exports = window; |
|
|
|
exports.dot = dot; |
|
exports.sum = sum; |
|
exports.foldl = foldl; |
|
exports.Cont = Cont; |
|
exports.T = T; |
|
exports.Monad = Monad; |
|
exports.cofoldl = cofoldl; |
|
exports.cohelper = cohelper; |
|
exports.forever = forever; |
|
exports.List = List; |
I can't find the "do-notation" in this.