http://ryani.livejournal.com/ ([identity profile] ryani.livejournal.com) wrote in [personal profile] pozorvlak 2007-09-03 04:17 am (UTC)

Continuation Passing Style

Tail-call elimination is nice when the tail is known statically, but it is, as you said, just an optimization at that point.

It becomes much more interesting (and important!) when you don't statically know what the tail-call will be.

For example, consider embedding a Prolog-like logic language into Haskell. The easiest way I've seen to implement backtracking is by passing a "success" and "failure" continuation around. (see http://okmij.org/ftp/papers/LogicT.pdf)

-- success continuation
type SK ans a = a -> FK ans -> ans
-- failure continuation
type FK ans = ans

-- LogicT is a monad transformer, where m is the type of the
-- monad to be transformed.  For example, LogicT IO a could 
-- include side effects as part of the computation of a
-- SFKT = "success/failure continuation thread"
newtype LogicT m a = SFKT (forall ans. SK (m ans) a -> FK (m ans) -> m ans)
See the paper for the rest of the details on how this is a Monad and how to use it to implement MonadPlus and a set of other interesting operations like "fair disjunction".

However, these continuation-passing styles rely heavily on the fact that tail-calling a continuation function runs in constant stack space.

Post a comment in response:

This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting