我正在编写一个需要递归分析“命令”和“程序”列表的程序(它是我们的教授为生活在迷宫中的机器人发明的一些“机器人语言”的翻译) . 因为我的初始实现太慢,所以我决定使用call-with-current-continuation .
我知道call / cc是如何工作的,我已经阅读this和this作为解释 .
我的电话/ cc基于这部分教程:
通常我们希望使用call-with-current-continuation来调用一些带有转义而不是转义过程的过程 . 例如,我们可能有一个除了转义过程之外还带有两个参数的过程,因此:(define(foo xy escape)...(if(= x 0)(escape'ERROR))...))我们可以修复通过讨论程序,使其成为一个参数的过程 . [前一章应讨论讨论! ]假设我们想要传递0和1作为x和y的值,以及将foo传递给转义过程 . 我们说(调用with-current-continuation(lambda(escape)(foo 0 1 escape))而不是说(call-with-current-continuation foo)没有传递足够的参数来调用foo . lambda表达式创建一个完全符合我们想要的闭包 . 它将使用参数0,1调用foo,并使用call-with-current-continuation创建转义过程 .
但是,由于某种原因它不起作用并抛出此异常:
call-with-current-continuation: contract violation
expected: (any/c . -> . any)
given: #<procedure:...mazesimulator.ss:301:34>
我希望你能帮助我找出错误并解释为什么会发生......
以下是与此问题相关的代码部分:
; main program
(define (simulate state expression-list program limit)
; read the input and set global variables
(set! current-orientation (list-ref state 2))
(set! current-coordinates (list-ref state 1))
(set! current-maze (list-ref state 0))
; call the inner function
(call-with-current-continuation (lambda (exit)
(command state expression-list program limit exit)))
; this is the output
(list list-of-executed-commands (list current-maze current-coordinates current-orientation))
)
;; main recursive function
;; analyses expression-list parameter
;; evaluates its elements
;; and calls itself on the cdr of the espression-list
(define (command state expression-list program limit exit)
(if (and (not (null? expression-list))(equal? stop-command #f))
; recursion end condition, the whole procedure will be done only
; if the list is still not empty
(if (atom? expression-list) ;if the list consists of only one command
(if (equal? stop-command #f) ;positive branch - if there were no erros before
(atomic-command state expression-list program limit exit) ;call atomic-command on this element
;when flag is set to #t
(exit))
; here comes a problem with "inner ifs"
(if (atom? (car expression-list)) ;negative branch - if the first element is "if"
(if (equal? (car expression-list) 'if) ;if the list consisits only of if-clause, no other commands ((if ...))
(if ((name->function (list-ref expression-list 1))) ;evaluate the boolean - wall? north? and choose corresponding branch
(command state (list-ref expression-list 2) program limit exit)
(command state (list-ref expression-list 3) program limit exit))
(evaluate-first-and-call-command-on-rest expression-list program limit exit))
(if (equal? (car(car expression-list)) 'if) ;if the if-clause is not the only element in list - "inner if" ((if ...) turn-left put-mark)
(begin ;not only evaluate if-clause,
(if ((name->function (list-ref (car expression-list) 1)))
(command state (list-ref (car expression-list) 2) program limit exit)
(command state (list-ref (car expression-list) 3) program limit exit))
(command state (cdr expression-list) program limit exit)) ;but also call command on cdr!
(evaluate-first-and-call-command-on-rest expression-list program limit exit))))
;when limit is exceeded or when the flag is set to #t
(exit) ))
2 回答
新的后续行动:所以在这一点上我对海报的问题感到困惑 . GoZoner已指出
call/cc
传递的延续可能在调用时需要一个实际参数,但在Racket中这通常不正确(基于海报的错误消息,我假设正在讨论的语言实现) .此外,原始海报放入问题的代码片段不完整,因此无法直接执行代码以尝试复制问题 . (我的非正式分析并未发现原始海报所提出的使用
call-with-current-continuation
的明显错误 . )如果原始海报可以推导出暴露相同问题的最小(或至少更小)测试用例,那将是有用的 . .可能是Racket中的一种特定语言或语言级别使用了更具限制性的形式
call/cc
,但我还没有找到这种语言级别的证据 . 我将向原始海报提出问题 .编辑:Chris-Jester Young指出我的评论可能不适用于此(请参阅对此答案的评论) . 我需要更仔细地调查Racket对强制性代码中延续的处理;下面的注释可能会引导提问者走错路 . (如果我能确认下面的笔记是假的,我打算删除这个答案 . )
后续编辑:看起来Racket对
call/cc
的处理确实传递了一个延续,当从丢弃该值的上下文中调用它时,它将接受零值 . 例如:以上打印385(两次);一次为
(* 5 7 11)
,一次为(hi)
.(原评论如下)
你使用零参数调用
(exit)
的事实让我认为你并不完全理解call/cc
如何工作(如在其可观察的行为中),尽管你声称相反 .在您尝试将
call/cc
纳入您的解决方案之前,我建议您使用一些小例子,完全独立于教授的机器人迷宫基础设施 .例如,我可以通过这种方式轻松重现您的错误消息:
从上面,我得到:
这与您的错误消息非常相似,不是吗? (虽然说实话,这可能只是巧合) .
将上面运行的输出与运行的输出进行比较:
和:
和:
和:
仔细考虑每个人所说明的内容,并考虑一下你的程序如何重要 .
call / cc 'escape procedure'需要一个参数 . 您将其称为
(exit)
,没有必需的参数 . 不同的Scheme实现将以不同方式处理它 . 这是抱怨的一个:'escape procedure'期望值的原因是
call/cc
,就像所有Scheme一样功能,需要产生 Value . 提供的参数是调用转义过程时call / cc的返回值 .