+4  A: 

Continuation capture the state of a computation, to be invoked later.

Think of the computation between leaving the shift expression and leaving the reset expression as a function. Inside the shift expression this function is called k, it is the continuation. You can pass it around, invoke it later, even more than once.

I think the value returned by the reset expression is the value of the expression inside the shift expression after the =>, but about this I'm not quite sure.

So with continuations you can wrap up a rather arbitrary and non-local piece of code in a function. This can be used to implement non-standard control flow, such as coroutining or backtracking.

So continuations should be used on a system level. Sprinkling them through your application code would be a sure recipe for nightmares, much worse than the worst spaghetti code using goto could ever be.

Disclaimer: I have no in depth understanding of continuations in Scala, I just inferred it from looking at the examples and knowing continuations from Scheme.

starblue
+11  A: 

My blog does explain what reset and shift do, so you may want to read that again.

Another good source, which I also point in my blog, is the Wikipedia entry on continuation passing style. That one is, by far, the most clear on the subject, though it does not use Scala syntax, and the continuation is explicitly passed.

The paper on delimited continuations, which I link to in my blog but seems to have become broken, gives many examples of usage.

But I think the best example of the concept of delimited continuations is Scala Swarm. In it, the library stops the execution of your code at one point, and the remaining computation becomes the continuation. The library then does something -- in this case, transferring the computation to another host, and returns the result (the value of the variable which was accessed) to the computation that was stopped.

Now, you don't understand even the simple example on the Scala page, so do read my blog. In it I'm only concerned with explaining these basics, of why the result is 8.

Daniel
I re-read your blog entry and this time I stuck with it -- I think I have a better idea of what is going on. I didn't get much from the Wikipedia page (I already know Lisp continuations) but the reset/shift deferred style or whatever its called had me stumped. For the impatient (ie myself) your description was ok but people will have to make sure to stick with it up to the "The result of reset is the result of the code inside shift." paragraph... I was hopelessly lost until that point but it does get clearer! I will have a look at Swarm because I'm still curious what this is for. Thx!
Dave
Yes, it does take time until things start making sense. I didn't feel I could get away making the explanation any faster.
Daniel
It all came together for my when I came to the realization that "reset delimits the scope of the continuation. (ie: the variables and statements to be included.)
JeffV
+4  A: 

I found the existing explanations to be less effective at explaining the concept than I would hope. I hope this one is clear (and correct.) I have not used continuations yet.

When a continuation function cf is called:

  1. Execution skips over the rest of the shift block and begins again at the end of it
    • the parameter passed to cf is what the shift block "evaluates" to as execution continues. this can be different for every call to cf
  2. Execution continues until the end of the reset block (or until a call to reset if there is no block)
    • the result of the reset block (or the parameter to reset() if there is no block) is what cf returns
  3. Execution continues after cf until the end of the shift block
  4. Execution skips until the end of the reset block (or a call to reset?)

So in this example, follow the letters from A to Z

reset {
  // A
  shift { cf: (Int=>Int) =>
    // B
    val eleven = cf(10)
    // E
    println(eleven)
    val oneHundredOne = cf(100)
    // H
    println(oneHundredOne)
  }
  // C execution continues here with the 10 as the context
  // F execution continues here with 100
  + 1
  // D 10.+(1) has been executed - 11 is returned from cf which gets assigned to eleven
  // G 100.+(1) has been executed and 101 is returned and assigned to oneHundredOne
}
// I

This prints:

11
101
Alex Neth