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.