Logo Questions Linux Laravel Mysql Ubuntu Git Menu

What do "continuations" mean in functional programming?(Specfically SML)

I have read a lot about continuations and a very common definition I saw is, it returns the control state.

I am taking a functional programming course taught in SML.

Our professor defined continuations to be:

"What keeps track of what we still have to do" ; "Gives us control of the call stack"

A lot of his examples revolve around trees. Before this chapter, we did tail recursion. I understand that tail recursion lets go of the stack to hold the recursively called functions by having an additional argument to "build" up the answer. Reversing a list would be built in a new accumulator where we append to it accordingly. Also, he said something about functions are called(but not evaluated) except till we reach the end where we replace backwards. He said an improved version of tail recursion would be using CPS(Continuation Programming Style).

Could someone give a simplified explanation of what continuations are and why they are favoured over other programming styles?

I found this stackoverflow link that helped me, but still did not clarify the idea for me:

I just don't get continuations!

like image 752
Ralph Avatar asked Mar 17 '23 19:03


1 Answers

Continuations simply treat "what happens next" as first class objects that can be used once unconditionally, ignored in favour of something else, or used multiple times.

To address what Continuation Passing Style is, here is some expression written normally:

let h x = f (g x)

g is applied to x and f is applied to the result. Notice that g does not have any control. Its result will be passed to f no matter what.

in CPS this is written

let h x next = (g x (fun result -> f result next))

g not only has x as an argument, but a continuation that takes the output of g and returns the final value. This function calls f in the same manner, and gives next as the continuation.

What happened? What changed that made this so much more useful than f (g x)? The difference is that now g is in control. It can decide whether to use what happens next or not. That is the essence of continuations.

An example of where continuations arise are imperative programming languages where you have control structures. Whiles, blocks, ordinary statements, breaks and continues are all generalized through continuations, because these control structures take what happens next and decide what to do with it, for example we can have

while(condition1) {
    if(condition2) break;
    if(condition3) continue;
return statement3;

The while, the block, the statement, the break and the continue can all be described in a functional model through continuations. Each construct can be considered to be a function that accepts the

  • current environment containing
    • the enclosing scopes
    • optional functions accepting the current environment and returning a continuation to
      • break from the inner most loop
      • continue from the inner most loop
      • return from the current function.
  • all the blocks associated with it (if-blocks, while-block, etc)
  • a continuation to the next statement

and returns the new environment.

In the while loop, the condition is evaluated according to the current environment. If it is evaluated to true, then the block is evaluated and returns the new environment. The result of evaluating the while loop again with the new environment is returned. If it is evaluated to false, the result of evaluating the next statement is returned.

With the break statement, we lookup the break function in the environment. If there is no function found then we are not inside a loop and we give an error. Otherwise we give the current environment to the function and return the evaluated continuation, which would be the statement after the the while loop.

With the continue statement the same would happen, except the continuation would be the while loop.

With the return statement the continuation would be the statement following the call to the current function, but it would remove the current enclosing scope from the environment.

like image 54
Reuben Steenekamp Avatar answered Apr 07 '23 05:04

Reuben Steenekamp