Live data from Hacker News

Writing a Lisp: Continuations

reinvanderwoerd.nl

31–40 of 51 posts

Re: Writing a Lisp: Continuations

#31

Earlier quoted context omitted.

C# has async/await and TPL, e.g. .ContinueWith(...) Javscript has promises and async/await

If anyone can feedback on why my comment is wrong I'd appreciate it. I know we're not meant to comment on downvoting but I want to uncover the error in my understanding of this subject because at least 3 people downvoted but there is no reply yet??

Async/await does not allow you to suspend a computation and then resume it, and it is not easy to chain.

Re: Writing a Lisp: Continuations

#32

Earlier quoted context omitted.

Here's the obligatory "Haskell has a monad for that" comment http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Mo...

That kind of feels like cheating though. I mean, the complicated part of a continuation is that it restores the same context and state that the app had right before the plunge. But Haskell inherently doesn't have "floating" state, it's all self-contained within each parameter. So in Haskell it's more or less a fancy goto-statement.

The linked module defines a "monad transformer" that can wrap other monads with a continuation-capturing layer. This means, among other things (Haskell's solution is awesomely general) that you can indeed use it with state, if you compose it with the state monad, or even the IO monad.

(The bottom of the documentation page has a contrived example of this.)

Re: Writing a Lisp: Continuations

#33

Earlier quoted context omitted.

If anyone can feedback on why my comment is wrong I'd appreciate it. I know we're not meant to comment on downvoting but I want to uncover the error in my understanding of this subject because at least 3 people downvoted but there is no reply yet??

Async/await does not allow you to suspend a computation and then resume it, and it is not easy to chain.

Thanks.

I took continuation to include cases where you respond to asynchronous call backs while the program is still executing, in which case suspension isn't needed.

Re: Writing a Lisp: Continuations

#34

Earlier quoted context omitted.

If anyone can feedback on why my comment is wrong I'd appreciate it. I know we're not meant to comment on downvoting but I want to uncover the error in my understanding of this subject because at least 3 people downvoted but there is no reply yet??

Async/await does not allow you to suspend a computation and then resume it, and it is not easy to chain.

If you implement your own awaiter with INotifyCompletion [1], you get the continuation as an Action that you can invoke as you will. TBH I haven't done it, but I believe you could use that to implement something akin to call/cc.

[1] https://msdn.microsoft.com/en-us/library/system.runtime.comp...

Re: Writing a Lisp: Continuations

#35
post #8

Do any non-Lisp/Scheme languages have continuations?

The Rhino javascript implementation has continuations. Chris Double once stuck it in Jetty, and I threw together a horrifying proof-of-concept Seaside-like continuation-based web programming library based on that: http://homepages.kcbbs.gen.nz/tonyg/lshift_archive/a-rhino-a... As a proof-of-concept, it was fun, but that's as far as it went :-)

Rhino was a fun JS system. One of the continuation examples I did for a talk was migrating threads in Rhino: https://bluishcoder.co.nz/2006/06/11/migrating-javascript-th.... Start a thread on one machine, serialize the continuation and send it across the network and resume it on that machine.

Re: Writing a Lisp: Continuations

#36
post #12

Continuations are strangely underused, as they enables writing long-living processes in a simple way, without having to keep them in running in a thread, or even in memory. Then a real programming language can replace all "business processing" crap languages. Let's say you write a framework that escapes to a continuation whenever the "process" is waiting for Futures or Promises to complete, and returns the thread to…

I have implemented interpreters that support both full and delimited continuations. They are underused for many very good reasons. A continuation makes an implicit state machine. Implicit means anonymous, which means harder to talk about, which means harder to reason about. But there are technical problems too.

Continuation based sessions, as used in fringe web frameworks such as Seaside or even Arc's library that powers Hacker News, is a really problematic approach. Reifying a slice of call stack in to a continuation and serializing it introduces all sorts of problems for resource management and the user experience, especially in the presence of change.

For example, let's say you deploy a new version of your code: What happens to all the in-progress sessions? Do you let old code keep running? Do you force users to start over? Compare to "Edit and Continue" in a Java/C#/Smalltalk codebase where you can change a method and all instances get the new behavior, vs if you change a function that constructs another function: All the old closures stick around with the old code.

Let's say a user leaves a browser tab open for a while: How long do you wait before invalidating the session and free its resources? What impact does that have on the user experience? Hacker News has mostly eliminated its reliance on continuations to remedy these sorts of problems.

Speaking of resources: What resources does a continuation hold on to? If you serialize a continuation, do you keep all file handles open? Do you perform static analysis to know a priori what data should be garbage collected or excluded from the continuation as "semantic garbage"? This problem is double bad when laziness is involved. Consider paginating through a database cursor.

What happens when a continuation must be forked? Consider using a continuation-id to resume an interaction with a web app: Does opening a new tab duplicate any held resources by the continuation? Do your external resources even support cloning operations or are they thread safe? Compare to unix "fork" and file handles vs shared memory.

Re: Writing a Lisp: Continuations

#37

I remember trying to learn continuations during my CS degree, and evidently even today I still don't understand them. The examples don't seem to help either – how exactly does the control flow function?

Do you know setjmp/longjmp in C? It's like that, except you can longjmp to the same target more than once, because Scheme's equivalent of "stack frames" are on the garbage-collected heap instead of "the stack". (The implementation may be fancier, but that's the easiest way to do it.)

Re: Writing a Lisp: Continuations

#39

Earlier quoted context omitted.

There's lots of continuation styles & libraries, but most are delimited continuations. In my opinion, delimited ones are far cleaner to implement and to work with than the more universal continuations of Scheme. call/cc, as a product of Scheme's efforts on simplicity[1], has to encompass a larger amount of low-level state than most real-world uses of it use (and it's used far less frequently in "real applications" th…

Also, delimited continuations are no less general than the regular ones. Regular continuations are also delimited, because they cannot capture control beyond the program's startup function. If we place a prompt at the top of the main function of the program and use that for making delimited continuations, we basically get regular continuations: continuations that can potentially return all the way to the top, just as…

> If we place a prompt at the top of the main function of the program and use that for making delimited continuations, we basically get regular continuations: continuations that can potentially return all the way to the top, just as far as regular continuations.

While this is certainly true in theory, in practice it doesn't seem that simple. When you start dealing with already-compiled code (can't apply a macro to it), first-class (built-into the language) continuations will work as you'd expect but delimited not at all. That can be a serious practical restriction.

I'm not used to Common Lisp but I assume you can customize how the "compile" command in ASDF works so maybe you can wrap your entire program, ASDF requirements at all, in that, and that's convenient. But consider Clojure which has equally powerful macros, but whose require forms won't customize like that. You could have your program's compilation phase go through and recompile the entire Clojure distribution of course, but there's some things you can only consume as bytecode (like anything Java related) and obviously you can't help that via CPS transformation. You'll need to get into bytecode manipulation like Quasar does. Not unlike those libraries in the C world that translate blocking system calls into nonblocking system calls for fiber / green-thread / whatever-you-want-to-call-it usage.

Coincidentally, this is exactly the reason I've found Clojure's async module to be such a pain to work with, compared to Quasar.

Re: Writing a Lisp: Continuations

#40

Earlier quoted context omitted.

There's lots of continuation styles & libraries, but most are delimited continuations. In my opinion, delimited ones are far cleaner to implement and to work with than the more universal continuations of Scheme. call/cc, as a product of Scheme's efforts on simplicity[1], has to encompass a larger amount of low-level state than most real-world uses of it use (and it's used far less frequently in "real applications" th…

Any recommendations for write-ups on how delimited continuations are implemented?

Check out Andy wingo's blog. He implemented delimited continuations for guile, and provides lots of sources for his implementation.

And ofcourse everything by Oleg Kiselyov

Post reply on HN