C. Scott Ananian (2014-02-13T23:32:09.000Z)
forbes at lindesay.co.uk (2014-02-14T00:11:18.844Z)
For your consideration, here is an implementation of Monadic Promises, as a Promise subclass: (This version is inexpertly hand-rewritten into ES6; see https://gist.github.com/cscott/b1966d485807d9a8cc39 for an ES5 version which has been tested to work against https://github.com/paulmillr/es6-shim/pull/215) ```js class MonadicPromise extends Promise { constructor(exec) { // the promise constructor needs to be new each time, // in order to thwart the optimization in Promise.resolve // (formerly Promise.cast) class MP extends MonadicPromise { constructor(exec) { Promise.call(this, (f,r) => exec( v => f([v]), r)); } } return new MP(exec); }, then(f, r) { return super.then(v => f(v[0]), r); }, // XXX Note that I wouldn't have to override this if it weren't for the // check in step 8 of CreatePromiseCapabilityRecord. resolve(v) { return new MonadicPromise(function(r) { r(v); }); } }; MonadicPromise.prototype.monadic = true; // just for demonstration purposes // Let's test it out! MonadicPromise.resolve(5).then(function(x) { console.log('x is', x); // 5, of course. }); var resolve; new MonadicPromise(function(r) { resolve = r; }).then(function(x) { if (x.monadic) { console.log('this is another promise!'); return MonadicPromise.resolve(x); // wrap it again } }).then(function(x) { console.log('got', x); if (x.monadic) { console.log('still monadic'); return x; } }).then(function(x) { console.log('finally resolved', x); }); resolve(MonadicPromise.resolve(5)); ``` I hope this demonstrates that with the current spec you can, in fact, have your Monadic Promise cake, if that's your preference. I would suggest that the check in step 8 of CreatePromiseCapabilityRecord be rewritten to reassign the result of the constructor to `capability.promise`; that will make subclasses like this one a bit more straightforward to implement (without having to closely read the spec to figure out why TypeErrors are being thrown).