
Why Are Continuations So Confusing, and What Do They Really Do? - mk
http://idea-log.blogspot.com/2005/10/why-are-continuations-so-confusing-and.html
======
pc
His hypothetical continuations don't quite work.

    
    
      theSite = mark();
      puts "Hello, World!"
      theSite.return();
    

This is the first example in the post, and one which it's claimed will loop
continually. Translating to Scheme (where we can actually run the pseudo-
code):

    
    
      (begin
        (define theSite #f)
        (set! theSite (call/cc (lambda (c) c)))
        (print "Hello, World!") (newline)
        (theSite #f))
    

And we get:

    
    
      > (begin
          (define theSite #f)
          (set! theSite (call/cc (lambda (c) c)))
          (print "Hello, World!") (newline)
          (theSite #f))
      "Hello, World!"
      "Hello, World!"
      procedure application: expected procedure, given: #f; arguments were: #f
    

This translation to Scheme seems fair, since the definition of mark()
explicitly states that it "allows you to pass information back to the original
site, so that it evaluates to a different value" -- which means that the
return value of mark() itself is clearly significant, and therefore that the
step of "set theSite to the result of evaluating the current form" is
considered part of the continuation (or "mark").

In this case, theSite gets set to #f, and the continuation is then "broken".

It might seem tedious to nitpick here, but continuations are so mysterious
exactly because of these issues. mark() _can't be fixed_ without drastically
changing the semantics of continuations. This is kinda non-obvious, and
something that people often discover suddenly when wondering why call/cc is
implemented in such a roundabout fashion.

Continuations are confusing to point where even toy examples in pedagogical
blog posts are easy to mess up.

~~~
jcl
What Scheme are you running this with? I tried your code in DrScheme, and it
prints "Hello, World!" exactly once, with no error, no infinite loop. I'm not
sure why, but I expect it has something to do with the semantics of "begin"
(maybe a bug in DrScheme?); you can make the code work in DrScheme as you
describe if you use "let" instead of "begin":

    
    
      (let ((cont #f)) 
        (set! cont (call/cc (lambda (k) k)))
        (print "Hello, world!")
        (cont #f))
    

You can get an infinite loop by changing where the variable is set:

    
    
      (let ((cont #f)) 
        (call/cc (lambda (k) (set! cont k)))
        (print "Hello, world!")
        (cont #f))

------
dfranke
A few years ago, I woke up to my alarm, really groggy, and accidentally hit
alarm off when I meant to hit the snooze button. Then I thought to myself, "I
think I'll stay in bed for a few more minutes. I'll just remember my current
continuation and if I oversleep I'll call it back with an error".

I overslept.

~~~
dfranke
Coda: however, the professor whose class I missed the first 20 minutes of was
a lisper, so he got a good laugh out of my excuse.

------
jsmcgd
The following article is my functional programming bible. I always refer to it
when things start to get a little hazy.

<http://www.defmacro.org/ramblings/fp.html>

If you read it (the continuations section) you _will_ understand
continuations. I stake my HN reputation on it (whatever that's worth).

------
pg
The best way to understand continuations may be to think of them as copies of
the stack.

~~~
henning
does simulating state in http with continuations scale?

~~~
pg
It would depend on how much you used them. In News.YC I try to avoid using
even closures as much as I can. In the earliest versions I made practically
every link on every page be a closure. The source is so simple that way. But
keeping that many closures around (in case the user hits the back button a
couple times then makes another choice) soon became unwieldy. You rapidly find
you have a couple hundred thousand closures in memory. So now whenever I can
conveniently get all the state I need into the arguments of a url, I do that.

You can see which links need to be closures by mousing over them. If the link
looks like r?fnid=hashkey, it's a reference to a closure on the server.
Usually it means there is something that has to be done after whatever the
link does.

Though Arc has continuations, I haven't needed to use them anywhere in News
yet (except for catch and throw, which is a degenerate case). Nothing has
state that complicated.

------
SwellJoe
I found this explanation far more confusing than a good explanation of
continuations (of which I've seen several). And giving them a new name is bad
mojo.

I believe the brief description being derided in this article, "the remaining
work to be done", would be fine if it included the important bit: state. As he
rightly points out, the work isn't the important bit...it's the state of the
work+data that matters in continuations, and I didn't find his explanation
really made that as clear as several other tutorials out there. Comparing it
to goto was particularly uncomfortable for me (because again, it's the state
that matters...and goto is effectively stateless in this context, and has the
same flaw as just saying "the remaining work to be done"). The key to
continuations is that you pick up where you left off with all data (the stack,
as pg points out) intact.

So, pg has it right, of course, but I'm not sure very many dynamic language
developers really have a very good comprehension of "the stack".

~~~
jules
Continuations don't save "state", so his explanation is entirely right. Also,
the mark() and return() operations (which are like goto) do save the
environment, unlike gotos. That's why you can return() back into a procedure.
You can't goto back into a procedure (well, in assembly you can but your
variables will be gone).

~~~
SwellJoe
Environment is not state? I'm afraid we have different definitions of state,
then.

~~~
jules
State genererally means the state of mutable things. Invoking a continuation
will not reset the things you mutated, it will only reset the variables to
their memory locations (in fact it does not "reset", the variables are still
there). It's the same as with a closure:

    
    
        (let ((x 2))
          (let ((closure (lambda () (print x))))
            (set! x 4)
            (closure))) ; prints 4 not 2
    

The closure doesn't remember the old value of x, it just remembers the memory
location.

~~~
SwellJoe
I never said anything about resetting variables, and in fact, I emphatically
mentioned copying the stack by way of clarification. I'm surprised you would
misinterpret me to be saying anything about resetting variables. I'll try to
refrain from using "state" in the future, when speaking to someone that could
be from a functional programming background, since it seems to be so easy to
misinterpret as "variables". I wasn't aware anyone used the term "state" to
mean "variables", but I come from a C-derived lineage, and may have missed
that memo.

I'll also try to refrain from commenting in language weenie threads. It's not
my forte.

------
sah
This is a very out-of-fashion confusing concept on which to write tutorials in
your blog! Monads are the new continuations. Try to keep up.

