Continuations

We use the greek letter κ (0x03BA) to represent the current continuation.

Principle

Function with one arguments

; Normal style
(not T)

; Continuation-passing style
(define (notcps v κ) (k (not v)))

Function with two arguments

; Normal style
(add 1 2)

; Continuation-passing style
(define (add a b κ) (κ (+ a b)))

Singly-nested functions

; Normal style
(define (fn) (add (mul 1 2) 3)

; Continuation-passing style
(define (add a b κ) (k (+ a b)))
(define (mul a b κ) (k (* a b)))

(define (fn κ) (mul 1 2 (lambda (x) (add x 3 κ)))

Doubly-nested functions

; Normal style
(define (fn) (add (mul 1 2) (div 3 4)))

; Continuation-passing style
(define (add a b κ) (k (+ a b)))
(define (mul a b κ) (k (* a b)))
(define (div a b κ) (k (/ a b)))

(define (fn κ) (mul 1 2 (lambda (x) (div 4 2 (lambda (y) (add x y κ))))))

Control structures

If-Then-Else

; Normal style
(define (fn v)
    (if (equ v 0)
        (add v 1)
        (sub v 1)))

; Continuation-passing style
(define (fn v κ)
    (equ v 0 (lambda (x)
        (if x
            (add v 1 κ)
            (sub v 1 κ)))

Evaluation

The continuation-passing style represent a function call as a chain of continuation-accepting functions f(..., κ) where the function of rank N-1 is used as the continuation of the function of rank N.

Function with two arguments

Step Description
1 Apply current continuation to the result
2 Lift the second argument
2 Lift the first argument

Tree view

(define (fn κ)
    (mul
        1   ; immediate
        2   ; immediate
        (kappa (x) (div     ;.......................................................< continuation_2
                        4   ; immediate                                             |
                        2   ; immediate                                             |
                        (kappa (y) (add     ;....................< continuation_1   |
                                        x   ; closure variable   |                  |
                                        y   ; argument variable  |                  |               
                                        κ   ; closure variable   |                  |
                        )))                                      |                  |
                    ))                                                              |
    ))

ABI view

Types

struct _continuation_t;

typedef union _value_t {
  int64_t integer;
  char * string;
  void (*continuation)(union _value_t * environment, union _value_t result);
}
value_t;

typedef value_t environment_t[16];

typedef void (*continuation_t)(environment_t environment, value_t result);

Basic functions

void fn_add(environment_t E, value_t A0, value_t A1, continuation_t K) {
  const register value_t result = { .integer = A0.integer + A1.integer };
  K(E, result);
}

void fn_mul(environment_t E, value_t A0, value_t A1, continuation_t K) {
  const register value_t result = { .integer = A0.integer * A1.integer };
  K(E, result);
}

void fn_div(environment_t E, value_t A0, value_t A1, continuation_t K) {
  const register value_t result = { .integer = A0.integer / A1.integer };
  K(E, result);
}

Continuations

void cont_1(environment_t E, value_t Y) {
  fn_add(E, E[1], Y, E[0].continuation);
}

void cont_2(environment_t E, value_t X) {
  register const value_t A0 = { .integer = 4 };
  register const value_t A1 = { .integer = 2 };
  E[1] = X;
  fn_div(E, A0, A1, cont_1);
}

void print(environment_t E, value_t X) {
  printf("Hello %lld\n", X.integer);
}

Top and main

void fn(environment_t E, continuation_t K) {
  register const value_t A0 = { .integer = 1 };
  register const value_t A1 = { .integer = 2 };
  E[0].continuation = K;
  fn_mul(E, A0, A1, cont_2);
}

int main(const int argc, char ** const argv) {
  /*
   * Create an empty environment.
   */
  environment_t env;
  memset(env, 0, sizeof(env));
  /*
   * Call the function.
   */
  fn(env, print);
  return 0;
}