kevin kelley

engineer@large

Follow me on GitHub

Continuation-Passing Style ** CPS transformation (Steele, Lambda the Ultimate xxx, Rabbit compiler) is a basic and powerful idea. With closures and CPS you can for ex. implement procedure calls, tail recursion, actors…

Converting a function call to CPS: consider: ‘ Int i->Float fn { return i*11f }’. Normally: ‘f(2) => 22’. Call the fn with an int, and it executes and returns a float to the point of call. In CPS there’s no return: instead you pass an extra parameter, the “continuation”; and the fn instead of “return”ing its value, will call the continuation with it. So, instead of a stack model, push args and pop return, there’s no going back: you just keep moving forward to the next continuation.
So ‘fn’ becomes ‘ Int i, Float c { c(i*11f) }’; and with a simple “echo” continuation like ‘c := Float f {echo(f)}’, the call to ‘fn’ becomes ‘fn(2,c) => 22’. No big deal, it’s a mechanical transformation; it’s just that it’s pervasive – now, everything that touches ‘fn’ has also to be converted to CPS. Surely we don’t want to be doing such transformations by hand.

Enter the monad. Monads are about combining computations according to rules; maybe we can make a Continuation Monad that will handle the connectivity, so we can continue to write functions the normal way, and use the monad to connect them together.

For an example, think about a simple web-app, as compared to a console app. In the simplest kind of console app, you’d maybe start, print some options, wait for input, execute a selected action, and repeat.

In a web-app, it’s not like that. Http is stateless, so you’ll have to handle your own session tracking; and you can’t just have the server sitting waiting at the prompt for the user to respond.