
By example: Continuation-passing style in JavaScript  - budu
http://matt.might.net/articles/by-example-continuation-passing-style/
======
nix
What the author is missing: tail recursion in constant space is an implicit
requirement for practical use of CPS transformations. In fact this is probably
the single biggest reason for wanting efficient tail calls in a language.

ECMA doesn't require efficient tail recursion. Caveat programmer.

~~~
mattmight
Good point. True.

If you're going to do real CPS programming in JavaScript, you'll want to use a
trampoline or a timer mechanism to reset the stack.

But, in most cases, you do a little computation and then block waiting for an
event.

When the continuation gets invoked by the event-handling loop, the stack is
reset.

~~~
nix
_When the continuation gets invoked by the event-handling loop, the stack is
reset._

You're not compiling to C here: "the stack" may be a chain of heap-allocated
activation records that are still live as far as GC is concerned. What you're
describing might work but you'd want to test it to be sure.

EDIT: On reflection I agree that the setTimeout() approach should free the
stack, however it's implemented.

------
tomn
Twisted (a python asynchronous network programming framework) does something
similar, but inverted. Twisted functions return a Deferred object without
blocking. A Deferred is a promise of a value, so rather than passing the
callback into the function, you register a callback with the deferred, and the
function promises to call it later.

This type of thing has a few nice properties -- you can easily register more
than one callback, as well as using them as a pipeline (kind-of like monads in
haskell), which are awkward to implement with callbacks.

As an aside, in python you can trick generators into turning synchronous-
looking code into asynchronous, which can actually make things look a lot
neater if done properly -- i'll provide code if anyone's interested.

~~~
viraptor
> python you can trick generators into turning synchronous-looking code into
> asynchronous

Example: <http://dieselweb.org/lib/> or <https://github.com/saucelabs/monocle>

Although Diesel2 is much more interesting, with greenlets support. No more
messing about with `yield`, since the blocking functions themselves force a
context switch. <https://github.com/jamwt/diesel>

~~~
tomn
That looks really interesting, though it seems a bit dangerous -- greenlet
feels like a bit of a hack.

I wish I'd found diesel before twisted; it seems a lot more elegant if you
don't need any of the built-in protocols. The twisted model is good, there's
just too much of it.

------
ajro
Could someone explain how the 'call/cc in javascript' from the article is
supposed to be used?

    
    
      function callcc (f,cc) { 
        f(function(x,k) { cc(x) },cc);
      }

~~~
mattmight
Suppose you wrote a compiler that translates to JavaScript in continuation-
passing style. (Or suppose you wrote all your JavaScript in continuation-
passing style.)

That's the implementation of call/cc.

For how to use call/cc, I recommend my other article on continuations:

[http://matt.might.net/articles/programming-with-
continuation...](http://matt.might.net/articles/programming-with-continuations
--exceptions-backtracking-search-threads-generators-coroutines/)

~~~
ajro
I found this link before posting the question but I still can't imagine how to
use javascript call/cc implementation from your article (on the other hand I
think I know how to use call/cc in scheme). Maybe I am too tired today.

If you posted a simple example of JavaScript written in continuation-passing
style and using this call/cc implementation probably everything would be
clear.

------
ximeng
People interesting in this article might also like Eric Lippert's articles on
the subject.

[http://blogs.msdn.com/b/ericlippert/archive/2010/10/21/conti...](http://blogs.msdn.com/b/ericlippert/archive/2010/10/21/continuation-
passing-style-revisited-part-one.aspx)

They're more from a language design perspective rather than the more practical
article here.

------
agscala
Basically, this article is just about what callbacks are and how they are all
nice and convenient?

~~~
mattmight
No. I think you're missing the point.

Continuations become a highly constrained kind of callback in continuation-
passing style.

Callbacks by themselves don't make for a nice intermediate format for
compilation, or a way to model exceptions or distributed computation.

They only gain these abilities when constrained as continuations in CPS.

~~~
silentbicycle
For good descriptions of using CPS as an intermediate representation in a
compiler, check out Appel's _Compiling with Continuations_, Guy L. Steele's
"Rabbit" thesis, Krantz's "Orbit" thesis, and chapter 12 of the first edition
of _Essentials of Programming Languages_ (they cut it from later editions,
unfortunately). Appel uses ML, the rest use Scheme.

------
zackattack
doesn't jquery already do this with $.post?

