在过去的几天里,我一直在玩计划(特别是诡计)中的延续,并且对某些功能的结果感到有些困惑,并且想知道是否有人能够准确地解释这里发生了什么。
有一个名为(get-token)
的函数将检索给定文件中的下一个找到的标记。例如,如果接下来的3个标记是“a”,“b”和“c”,则调用(get-token)将在第一次调用时返回“a”,第二次调用时返回“b”,和“c”第三次被召唤。
我想要做的是有一个函数(peek-token)
,它将调用(get-token)
,返回令牌,然后返回调用(get-token)
函数之前的状态。我尝试了许多不同的方法来实现这个结果,而我现在拥有的是:
;; make things a little easier to write
(define-syntax bind/cc
(syntax-rules ()
((bind/cc var . body)
(call/cc (lambda (var) . body)))))
;; function should return next token and then
;; revert to previous state
(define (peek-token)
(bind/cc return
(let ((token (get-token)))
(return token))))
我现在如何理解,bind/cc
将在第一个return
保存延续,然后执行以下代码块。然后,当再次点击return
时,程序会跳回到延续绑定的位置,并且结果会给出token
值。
但是,当我运行上述函数时,结果与原始(get-token)
函数完全相同。
如果有人能够解释我出错的地方,或者表达更好的方法来获得相同的结果(我知道有些人讨厌通过电话/ cc的方式),我将非常感激。
答案 0 :(得分:4)
将马克·吐温错误引用为碎片:call/cc
的能力报告被夸大了。
更具体地说,call/cc
捕获呼叫状态,而非程序状态。这意味着它会捕获有关在调用continuation时代码流的位置的信息。它不捕获有关变量的信息,特别是,如果get-token
通过set!
变量保存其迭代状态,则在调用时不会恢复你的继续。
事实上,(call/cc (lambda (k) (let ((token (get-token))) (k token))))
的表达应该与(get-token)
的行为相同;两个表达式之间不应存在任何可观察到的差异。