1. Evaluation context = term with a hole in it. eval. context k ::= [] | k M | (lam x:A. M) k 2. The definition of evaluation contexts gives you a unique reduction strategy. Given a program M, you rewrite it as an evaluation context with another term. M = k { N } k describes 'the rest of the computation'. N describes the current focus of computation; so, a reduction rule should be applied to N. Let's say N --> N'. Then, we have k { N } ---> k { N' } In this way, we reduce a program. 3. When evaluating 'letcc u in M', u is bound to 'the rest of the computation', which is an evaluation context. k { letcc u in M } ---> k { [k/u] M } When throwing a value V to an evaluation context, the current evaluation context is canceled. k { throw V to k' } ---> k' { V } Thus, u : A false is bound to an evaluation context. 4. Example. Here is a function for computing the product of elements of a list: lam x : nat list. rec x of f nil => 1 | f (h::t) => if h = 0 then 0 else h * f(t) If the argument list contains 0, there is no more recursive calls (to see the rest of the list), but still we have to backtrack. This backtracking is avoided if we use 'letcc' and 'throw'. lam x : nat list. letcc u in rec x of f nil => 1 | f (h::t) => if h = 0 then throw 0 to u else h * f(t) Now consider the following program: ((lam x : nat list. letcc u in rec x of f nil => 1 | f (h::t) => if h = 0 then throw 0 to u else h * f(t) ) [1 :: 2 :: 0 :: nil] ) + 1 That is, we apply the function to [1 :: 2 :: 0 :: nil], and then add the result to 1. We first apply the function to [1 :: 2 :: 0 :: nil] which gives: ( letcc u in rec [1 :: 2 :: 0 :: nil] of f nil => 1 | f (h::t) => if h = 0 then throw 0 to u else h * f(t) ) + 1 Now what is the variable u bound to? (Please think about this.) It is bound to an evaluation context describing the rest of the computation, which is in this case "result + 1", i.e., "[] + 1". So, the above program reduces to: ( rec [1 :: 2 :: 0 :: nil] of f nil => 1 | f (h::t) => if h = 0 then throw 0 to ([] + 1) else h * f(t) ) + 1 Later when we encounter 0 in the list, we throw 0 to "[] + 1". So, no matter what the computation looks like at that point, we discard it and use the evaluation context "[] + 1". ...... throw 0 to ([] + 1) .... ---> 0 + 1 This is how evaluation context/letcc/throw works.