Last active
December 17, 2015 18:48
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.