3 ms·
It took a long time to grok continuations. There's an easy way to explain what they are: Imagine running a program in a VM. You know how you can take a snapsho
by sillysaurus3 9y ago
It took a long time to grok continuations. There's an easy way to explain what they are:
Imagine running a program in a VM. You know how you can take a snapshot and then restore to it later? That snapshot is equivalent to a continuation.
Another way of phrasing it is, it's your program frozen in time. You can snapshot your program and restore to that point later.
To put it technically, step through each call stack frame, serialize all the local variables, and you have yourself a continuation. To invoke it, call those functions in order and set the local variables to those values, then set the program counter to wherever it was. (You don't literally do this, but maybe that makes it easier to understand what's going on with it.)
The confusion: What about a database connection? Or a network connection of any kind? An open file handle? Etc. The answer is that those things can't be saved in a continuation.
The way that this works in Scheme is that there's a special primitive called "dynamic wind". It takes three callback functions: "before", "during", and "after". It invokes those callback functions in order. If execution leaves "during" for any reason whatsoever, then "after" is invoked.
Here's the kicker: If execution goes back into "during", then "before" is invoked. I.e. if you save a continuation inside "during," then "before" is the place that you'd put the code to re-initiate a database connection or re-open a file handle. Or fail.
And of course, no discussion of continuations would be complete without the argument for why call/cc is generally an anti-pattern: http://okmij.org/ftp/continuations/against-callcc.html http://okmij.org/ftp/continuations/against-callcc.html
Yet "On Lisp" presents several interesting ways to use them, and they are extremely powerful. One particular use is that you can implement cut, fail, and mark for non-deterministic backtracking. If you've used emacs lisp and you've ever written an edebug specification for how to debug a macro (https://www.gnu.org/software/emacs/manual/html_node/elisp/Specification-List.html#Specification-List https://www.gnu.org/software/emacs/manual/html_node/elisp/Sp...), some of the more complex features require backtracking: https://github.com/emacs-mirror/emacs/blob/0648edf3e05e224ee8410ab244df7364f919dc58/lisp/emacs-lisp/cl-macs.el#L2578-L2595 https://github.com/emacs-mirror/emacs/blob/0648edf3e05e224ee...
That's an area where continuations really shine, because the implementation can be just a few dozen lines compared to hundreds.
(elisp doesn't actually use continuations -- this is just an example of the territory they're useful in.)
- conistonwater 9y agoDo you find this explanation better or worse than the one that uses shift/reset and expressions with holes in them?
- sillysaurus3 9y agoI think everyone learns differently, and personally I'm a fan of the shotgun method: just explain it ten different ways till one of them clicks.
- DonaldPShimoda 9y agoI'm not OP, but my functional teacher (Matthew Flatt) taught continuations using the "holes". I really didn't get it at first; it was just a little too abstract for me. He had us implementing an interpreter, and step-by-step we were adding more features. Eventually we added continuations (building a CEK machine). It wasn't until I actually used the interpreter and played with it after finishing the homework that continuations started to make sense. But they really solidified for me a year later when I took a course in operational semantics from him. We walked through the evolution of semantics in various languages through history, and had to write out the evaluations of expressions step-by-step (by hand, on paper). Then continuations really made sense.
- notjack 9y agoIt's worth noting that the argument against call/cc is specifically against undelimited continuations. Delimited continuations, such as those created by the `shift` and `reset` control operators, do not suffer from the problems of call/cc.
- idibidiart 9y agoA very good explanation. See these two in order: // source: https://en.wikipedia.org/wiki/Call-with-current-continuation https://en.wikipedia.org/wiki/Call-with-current-continuation Criticism: Oleg Kiselyov, author of a delimited continuation implementation for OCaml and designer of an API for delimited stack manipulation for the implementation of control operators, advocates the use of delimited continuations instead of the full-stack continuations that call/cc manipulates: "Offering call/cc as a core control feature in terms of which all other control facilities should be implemented turns out a bad idea. Performance, memory and resource leaks, ease of implementation, ease of use, ease of reasoning all argue against call/cc"[3] Delimited Continuation: https://en.wikipedia.org/wiki/Delimited_continuation https://en.wikipedia.org/wiki/Delimited_continuation