这比看上去更简单。
首先,让我们重写它,给它一个更明显的名称,并用一个函数替换本地宏,以消除可能需要宏的任何混淆:
(define (yielder)
(define (control-state return)
(define (yield x)
(set! return (call/cc (λ (resume-here)
(set! control-state resume-here)
(return x)))))
(yield 1)
(yield 2)
(yield 3)
(return 'end))
(thunk (call/cc control-state)))
好的,首先要注意的是
(define (yielder) ...)
和
不
(define yielder ...)
所以
yielder
是一个函数,当被调用时将返回
(thunk ...)
:一个没有参数的函数。这意味着:
(define g (yielder)
原因
g
绑定到没有参数的函数。特别是
g
与
control-state
,也不是暂停的延续。由于函数尚未调用,因此尚未发生任何事情。进一步的
g
从未因任何分配而更改:
控制状态
绑定它关闭
是
突变,但
g
它本身就是nt。
所以,当
g
是
调用,则它立即调用的当前值
控制状态
带有当前continuation:一个函数,当被调用时,将立即从
call/cc
因此
g
:该函数绑定到
return
在…内
控制状态
。
控制状态
然后打电话
(yield 1)
开始评估
(set! return (call/cc (λ (resume-here)
(set! control-state resume-here)
(return x)))))
所以这需要打电话
(λ (resume-here)
(set! control-state resume-here)
(return x))
具有
resume-here
绑定到一个延续,如果调用该延续,将导致将其调用的值分配给
回来
.它将此延续隐藏到
控制状态
,然后调用的当前值
回来
值为
x
哪个是
1
。
回来
然后从该值返回
g
:作业尚未完成。
下次
g
它做同样的事情,创造一个新的
回来
continuation并调用的当前值
控制状态
以它作为论据。但这个价值现在是上次通话时藏在那里的延续。所以现在这个从
呼叫/cc
由于旧价值的调用而暂停
回来
并在继续之前完成任务。。。到下一个
yield
除了这次回来之外,哪个电话又跳了同样的舞
2
从…起
g
等等
从本质上讲,这两个连续部分表演了这种小的交错舞蹈,你每次都会听到
g
您正在创建一个新的continuation,说明如何从该调用返回,然后调用一个continuation来重新启动主体,在从返回之前为下一步隐藏一个新continuation
g
。
这很难理解,但如果你仔细研究一下,也不是不可能。