call-with-current-continuation: obtains its continuation and passes it to procedure. The continuation itself is represented by a procedure. Each time this procedure is applied to zero or more values, it returns the values to the continuation of the call/cc application. If procedure returns normally, the values returned by call/cc are the values returned by procedure.
non-local exit from recursion
(define product
(lambda (ls)
(call/cc
(lambda (break)
(let f ([ls ls])
(cond
[(null? ls) 1]
[(= (car ls) 0) (break 0)]
[else (* (car ls) (f (cdr ls)))]))))))
(((call/cc (lambda (k) k)) (lambda (x) x)) "HEY!")
((k (lambda (x) x)) "HEY!")
==> ;the continuation is: (lambda (x) x)
(((lambda (x) x) (lambda (x) x)) "HEY!")
==> "HEY!"
(let ([x (call/cc (lambda (k) k))])
(x (lambda (ignore) "hi")))
==> ; bind k to x
(k (lambda (ignore) "hi"))
==> ; the continuation is: bind k to x, apply x to (lambda ...)
((lambda (ignore) "hi") (lambda (ignore) "hi"))
==>
"hi"
let-values is a convenient way to receive multiple values and bind them to variables.
(let-values ([(a b) (values 1 2)] [c (values 1 2 3)])
(list a b c)) (1 2 (1 2 3))
values: accepts any number of arguments and simply return the arguments to its contiuation.
call-with-values: applies consumer to the values returned by invoking producer without arguments.
a continuation may accept zero or more than one value:
(call-with-values
(lambda ()
(call/cc (lambda (k) (k 2 3))))
(lambda (x y) (list x y))) ==> (2 3)
更复杂的例子:阴阳谜题
(let* ((yin
((lambda (cc) (display "@") cc) (call/cc (lambda (c) c))))
(yang
((lambda (cc) (display "*") cc) (call/cc (lambda (c) c)))))
(yin yang))
==> @*@**@***@****@*****@******@*******@********@*********@**...
对let绑定变量进行计算:
第一个: 生成lambda表达式l1, 由call/cc生成延续记做k1,
作为实际参数传入l1, 调用(l1 k1),副作用是打印
@, 返回值是k1, 绑定到变量名yin;
第二个: 生成lambda表达式l2, 由call/cc生成延续记做k2,
作为实际参数传入l2, 调用(l2 k2),副作用是打印
*, 返回值是k2, 绑定到变量名yang;
对let body进行计算:
变量名查找替换,结果是(k1 k2)。 (k1 k2)的意思是把k2返回到k1延续,即上面蓝色开始的:
调用(l1 k2), 打印
@,返回k2, 绑定到yin;
继续计算第二个: 生成lambda表达式l2', 由call/cc生成新的延续记做k3, 调用(l2' k3), 打印
*, 返回k3,绑定到yang;
继续对let body进行计算: 变量名替换,结果是(k2 k3)。(k2 k3)含义是把k3返回到k2延续,即上面红色开始的:
调用(l2 k3),打印
*, 返回k3, 绑定到yang;
继续对let body进行计算:变量名替换,注意k2环境下yin是k1, 结果是(k1 k3)。(k1 k3)是把k3返回到k1延续之处,即上面蓝色开始的:
调用(l1 k3), 打印*, 返回k3, 绑定到yin;
继续计算第二个: 生成lambda表达式l2'', 由call/cc生成新的延续记做k4, 调用(l2'' k4), 打印
@,返回k4, 绑定给yang.
继续对let body进行计算...
把上面绿色标记的顺序串起来就解释了阴阳谜题的输出。