2014-02-18 22 views
0

在过去的几天里,我一直在玩弄计划(特别是诡计)的延续,并且对于某些函数的结果感到有点困惑并且想知道是否任何人都可以解释到底发生了什么。计划:如何使用call/cc进行回溯

有一个名为(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)功能。

我会很感激,如果任何人都可以解释我要去的地方错了,或者表达一种更好的方法来获得相同的结果(我知道有些人讨厌去呼叫/立方厘米的方式)。

回答

4

乱砍马克·吐温错误引用到片:的call/cc的能力的报告严重夸大了。

更具体地,call/cc捕获呼叫状态,不编程状态。这意味着它会捕获有关调用延续时代码流向何处的信息。它还对变量捕获的信息,特别是,如果你的get-token通过set!婷变量中保存了它的迭代状态,这是不会当你调用你的持续恢复。

事实上,你的(call/cc (lambda (k) (let ((token (get-token))) (k token))))表达式应该相同的行为简单地(get-token);这两个表达式之间不应该有明显的差异。

+0

非常感谢你的帮助。我最终将'(peek-token)'函数放在我的扫描器文件中,并且只是跟踪文件指针,以便我可以从中重新读取令牌。出于好奇,你是否知道一种方法来捕获任一方案或CL中的实际程序状态?或者从来没有真正需要这个? – vikingsheepman

+0

除非我弄错了形式'(call-cc(lambda(k)...(k x)))'与'(begin ... x)'完全相同的任何形式。 – jozefg

+0

@jozefg非常多,假设这是继续使用的唯一地方。 –