Scheme 方案:如何使用call/cc进行回溯

Scheme 方案:如何使用call/cc进行回溯,scheme,callcc,Scheme,Callcc,在过去的几天里,我一直在玩scheme中的continuations(特别是guile),对一些函数的结果感到有点困惑,我想知道是否有人能够准确地解释这里发生了什么 有一个名为(get token)的函数,它将检索给定文件中找到的下一个令牌。例如,如果接下来的3个令牌是“a”、“b”和“c”,则调用(获取令牌)将在第一次调用时返回“a”,在第二次调用时返回“b”,在第三次调用时返回“c” 我想做的是让一个函数(peek token)调用(get token),返回令牌,然后返回到调用(get t

在过去的几天里,我一直在玩scheme中的continuations(特别是guile),对一些函数的结果感到有点困惑,我想知道是否有人能够准确地解释这里发生了什么

有一个名为
(get token)
的函数,它将检索给定文件中找到的下一个令牌。例如,如果接下来的3个令牌是“a”、“b”和“c”,则调用(获取令牌)将在第一次调用时返回“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
时保存一个continuation,然后执行下面的代码块。然后,当再次点击
return
时,程序跳回绑定continuation的位置,并给出
token

但是,当我运行上述函数时,结果与原始的
(get token)
函数完全相同


如果有人能解释我错在哪里,或者表达一种更好的方式来获得同样的结果,我将不胜感激(我知道有些人不喜欢走call/cc的方式)。把马克·吐温的一句错误引语砍成碎片:
call/cc
的功能报告被大大夸大了

更具体地说,
call/cc
捕获调用状态,而不是程序状态。这意味着它捕获了有关调用延续时代码流流向的信息。它不会捕获变量的信息,尤其是如果您的
get-token
通过
set保存其迭代状态设置一个变量,在调用continuation时不会恢复该变量


事实上,您的
(call/cc(lambda(k)(let((token(get token))))(k token))
表达式的行为应该与简单的
(get token)
相同;这两种表达方式之间不应该有任何明显的差异。

要把马克·吐温的一句错误引语驳得体无完肤:
call/cc
功能的报道被大大夸大了

更具体地说,
call/cc
捕获调用状态,而不是程序状态。这意味着它捕获了有关调用延续时代码流流向的信息。它不会捕获变量的信息,尤其是如果您的
get-token
通过
set保存其迭代状态设置一个变量,在调用continuation时不会恢复该变量


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

非常感谢您澄清这一点。最后,我把
(peek token)
函数放在我的scanner文件中,我只是跟踪文件指针,以便从中重新读取标记。出于好奇,您知道在scheme或CL中捕获实际程序状态的方法吗?或者根本就没有必要这样做?除非我弄错了,
(调用cc(lambda(k)…(kx))
的形式与
(begin…x)
@jozefg完全相同,假设这是唯一使用continuation的地方。非常感谢您澄清这一点。最后,我把
(peek token)
函数放在我的scanner文件中,我只是跟踪文件指针,以便从中重新读取标记。出于好奇,您知道在scheme或CL中捕获实际程序状态的方法吗?或者根本就没有必要这样做?除非我弄错了,
(调用cc(lambda(k)…(kx))
的形式与
(begin…x)
@jozefg几乎完全相同,假设这是唯一使用延续的地方。