Skip to content

Instantly share code, notes, and snippets.

@michaelsbradleyjr
Last active December 17, 2015 18:48
Show Gist options
  • Save michaelsbradleyjr/5655300 to your computer and use it in GitHub Desktop.
Save michaelsbradleyjr/5655300 to your computer and use it in GitHub Desktop.
The "yin-yang" call/cc puzzle ported from Scheme to JavaScript per jonas.
// jonas :: https://github.com/michaelsbradleyjr/jonas
// :: https://npmjs.org/package/jonas
var jonas = require("jonas"),
Cont = jonas.Monad.Cont,
pCont = jonas.Monad.pCont,
Q = jonas.Q,
util = require("util");
// see: http://en.wikipedia.org/wiki/Call-with-current-continuation
// for reference, here is the "yin-yang" call/cc puzzle as it's commonly
// implemented in Scheme:
// (let* ((yin
// ((lambda (cc) (display #\@) cc) (call-with-current-continuation (lambda (c) c))))
// (yang
// ((lambda (cc) (display #\*) cc) (call-with-current-continuation (lambda (c) c)))))
// (yin yang))
// we'll implement it twice in JavaScript, per jonas; the first implementation
// will be syncrhronous and the second one asynchronous
/* -------------------------------------------------------------------------- */
// Synchronous implementation - Cont monad
function λ(c) { return c(c); }
var mReturn = Cont.mReturn,
mFn = function (t) {
return function (cc) {
util.print(t);
return mReturn(cc);
};
};
Cont.callCC( λ ).mBind( mFn("@") )( Cont.callCC( λ ).mBind( mFn("*") ) );
// => @*@**@***@****@*****@******@*******@********@*********@**********@*****...
// will blow the call stack rather quickly; jonas is currently being revised so
// that synchronous monadic `run` does not involve recursion, i.e. it won't blow
// the stack, stay tuned...
// comment out the last line above in order to run the second implementation
// below
/* -------------------------------------------------------------------------- */
// Asynchronous implementation - pCont monad
mReturn = pCont.mReturn;
mFn = function (t, delay) {
return function (cc) {
util.print(t);
// since we're using pCont, we can introduce a variable delay
// in terms of a promise; resolution of the promises is
// handled automatically by the "monadic plumbing" of pCont;
// if delay is null or the value "s", the computation will
// implicitly make use of the JavaScript environment's
// setImmediate function per Q's contract re: `then`, owing to
// pCont's "inner monad" (pIdentity)
return mReturn(
( delay == null ) ||
( delay === "s" ) ? cc
: Q.delay(delay).then(
function () { return cc; }
)
);
};
};
pCont.callCC( λ ).mBind( mFn("@", 100) )( pCont.callCC( λ ).mBind( mFn("*", 100) ) );
// same output as above, but ~100ms delay between each character printed; won't
// blow the stack since each step in the monadic computation involves a trip
// across the event loop, but memory consumption is unbounded and the process
// will eventually crash
@CrypticSwarm
Copy link

Might want to add a note that you are implementing this twice. Once for the regular continuation monad and once for your promise continuation monad.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment