Very well written! A few basically inconsequential reading notes:
The List data type need not be lazy to have a monad, although it will obviously feel more Haskell like that way and lets one talk about generators, I suppose.
Promises are significantly more than just the continuation monad. It’s easy enough to describe, though, except we’ll have to be rid of the idea that the constructor itself is unit.
A value of type Cont is just a wrapper around a function which knows what to do with a continuation.
function Cont(contHandler) {
this.contHandler = contHandler;
};
For unit, this function merely passes the value to the continuation. Easy!
Cont.unit = function(value) {
return new Cont((continue) => continue(value));
};
We “eliminate” Cont values by providing a continuation to be passed to the wrapped continuation handler.
Binding is more complex. We’ll first consider a weird kind of identity on Conts. It’s quite convoluted, but you can see it does nothing more than construct a new Cont via a handler which runs the current Cont passing the provided continuation.
Cont.prototype.doNothing = function () {
return new Cont((resume) => this.run((value) => resume(value)));
};
which can be written in a less convoluted way as follows
Cont.prototype.doNothing = function () {
return new Cont((resume) => this.run(resume));
};
Finally, we’ll construct bind by a slight modification of the convoluted form of doNothing where we slip the transform function in at just the right time
Cont.prototype.bind = function (transform) {
return new Cont((resume) => this.run((value) => transform(value).run(resume)));
};
Notice that all we do is pass the value to transform which gives us a new Cont which we can immediately .run using the original continuation resume.
Very well written! A few basically inconsequential reading notes:
A value of type
Cont
is just a wrapper around a function which knows what to do with a continuation.For
unit
, this function merely passes the value to the continuation. Easy!We “eliminate”
Cont
values by providing a continuation to be passed to the wrapped continuation handler.The most natural way to run a
Cont
is to pass it a continuation which doesn’t do anything—it just returns immediately.Binding is more complex. We’ll first consider a weird kind of identity on
Cont
s. It’s quite convoluted, but you can see it does nothing more than construct a newCont
via a handler which runs the currentCont
passing the provided continuation.which can be written in a less convoluted way as follows
Finally, we’ll construct bind by a slight modification of the convoluted form of
doNothing
where we slip thetransform
function in at just the right timeNotice that all we do is pass the
value
totransform
which gives us a newCont
which we can immediately.run
using the original continuationresume
.(Here it is in de-ES6’d, copy-and-pasteable form: https://gist.github.com/tel/9a34caf0b6e38cba6772)