Understanding Let/cc and throw in racket

functional-programming, racket, scheme

Solution

Let's look at `let/cc` first.

The expression `(let/cc k e)` will 1) capture the current continuation (represented as a function) then 2) bind the variable `k` to the captured continuation and finally 3) evaluate the expression `e`.

A few examples are in order.

If during evaluation of the expression `e`, the captured contination `k` is not called, then the value of the `let/cc` expression is simply the value(s) to which the expression `e` evaluated to.

> (+ 10 (let/cc k 32)) 
42

If on the other hand `k` is called with a value `v` then the value of the entire `let\cc` expression becomes `v`.

> (+ 10 (let/cc k (+ 1 (k 2)))) 
12

Notice that the part `(+ _)` around the call `(k 2)` is skipped. The value is return to the continuation of `(let/cc ...)` immediately.

The most common use of `let/cc` is to mimic the control struct `return` known from many statement based languages. Here is the classical is-it-a-leap-year problem:

(define (divisible-by? y k)
  (zero? (remainder y k)))

(define (leap-year? y)
  (let/cc return
    (when (not (divisible-by? y 4))
      (return #f))
    (when (not (divisible-by? y 100))
      (return #t))
    (when (not (divisible-by? y 400))
      (return #f))
    #t))

(for/list ([y (in-range 1898 1906)])
  (list y (leap-year? y)))

Now what about `throw` ? That depends on which `throw` we are talking about. Is it the one from `misc1/throw` ?

Or perhaps the one from Might's article? http://matt.might.net/articles/programming-with-continuations--exceptions-backtracking-search-threads-generators-coroutines/

Or perhaps you are using the definition

(define (throw k v)
   (k v))

If the latter, then you can replace `(k v)` in my examples with `(throw k v)`.

UPDATE

Note that the continuation bound to `k` can be used more than once - it can also be used outside the `let/cc` expression. Consider this example:

(define n 0)
(let ([K (let/cc k k)])
  (when (< n 10)
    (displayln n)
    (set! n (+ n 1))
    (K K)))

Can you figure out what it does without running it?

Here is a "step by step" evaluation of the nested `let/cc` example.

(let/cc k0
  ((let/cc k1
     (k0 (sub1 (let/cc k2
                 (k1 k2)))))
   1))

(let/cc k0
  (k2 1))

(let/cc k0
 ((let/cc k1
     (k0 (sub1 1)))
   1))

(let/cc k0
 ((let/cc k1
     (k0 0))
   1))

0

Problem

In class we talked about two functions in racket i-e letcc and throw. The instructor said that let/cc has something to do with calling with the current continuation and throw just applies a to b e.g. ``` (throw a b) ``` I haven't been able to find much about these online. I did find a question asked for letcc on stackoverflow but I have not been able to understand the functioning of letcc from it completely. Could someone explain these two in simple words along with a simple example? Edit1: Also in my practice mid exam we are given two question related to it. For each of the following expressions that contain uses of let/cc, what is the value of each expression? ``` (let/cc k (throw (throw k 5) 6)) (let/cc k (throw k ((( lambda (x) x) k) (∗ 5 5)))) ``` The answers to these are 5 and 25 respectively. I just wanna understand the two concepts so that I can work with questions like these in my midterm exam.

Original source

Related problems