我正在攻读我大学的课程计划,同时看一些练习,我被困在这个特定的课程上 . 教授尚未回复我以前的邮件,因此我有更多机会在这里更快地收到答案 .
鉴于此代码
(define (list-iter-cc lst)
(call/cc
(lambda (return)
(for-each
(lambda (x)
(call/cc (lambda (next-step)
(return (cons x next-step)))))
lst)
'end)))
我必须使用它来编写其语法为的 iter
宏
(iter <a variable symbol> in <a list> <code>)
例:
(iter x in '(1 2 3)
(display x)
(newline))
因为我无法理解 list-iter-cc
我去看了解决方案,我也不明白 . 解决方案:
(define-syntax iter2
(syntax-rules (-> in)
((_ var in lst code ...)
(let loop ((head (list-iter-cc lst)))
(unless (eq? head 'end)
(let ((var (car head)))
code ...
(loop ((cdr head)))))))))
为了解开宏,我尝试编写以下内容
> (define head (list-iter-cc '(1 2 3 4)))
> head
'(1 . #<continuation>)
> (let ( (var (car head))) (display var))
1
> (define head2 (cdr head))
> (let ( (var2 (car head2)) ) (display var2))
Xxx X car: contract violation
expected: pair?
given: #<continuation>
>
这正是我认为会发生的事情 .
list-iter-cc
的返回继续在第一个lambda内的for-each的第一次迭代中被调用,返回 cons x next-step
. x
是列表的第一个元素, next-step
是延续 .
1) . next-step
的内容是什么? for-each
的以下迭代?如何在最后一次迭代后评估 'end
?
2) . 假设在宏 head (list-iter-cc lst)
中是 '(1 . #<continuation>)
,汽车是 1
并且它会显示,但是在循环到它的cdr之后, var (car head)
将是延续的汽车!它怎么可能评估 2
然后 3
然后 'end
,为什么这不会发生在我试着写的代码中去理解呢?
任何帮助将不胜感激,特别是可以指导我一步一步的帮助 .
1 回答
我们可以重写它
所以它是一个lambda函数,参数名为
lst
. 调用此函数时,lst
被设置为像往常一样保存函数调用的实际参数 . 然后,call/cc
设置名为return
的延续以保持当前的延续...这是什么?此时,接下来的事情就是将值返回给list-iter-cc
的调用者 .这意味着,调用
(return a)
会立即将a
的值返回给list-iter-cc
的调用者,就像函数list-iter-cc
完成其计算一样 .现在,
进入 . 它为列表
lst
中的每个元素调用其lambda参数,因此得到名称x
.那么,对于
lst
中的那个拳头,会发生什么?叫做 . 即它设置
next-step
来保持当前的延续并立即从整个函数list-iter-cc
返回!它返回了什么?这对
(x . <next-step>)
. 叫(next-step)
是什么意思?它意味着返回for-each
的主体,它将进入lst
中的下一个元素,如果有的话 . 如果没有,则退出for-each
的循环体,并且'end
通常作为函数list-iter-cc
的最后一个表达式的值返回,从而完成其计算!那么,我们如何使用它呢?例如,像这样:
当运行
(cdr a)
中的继续时,控件将跳回list-iter-cc
的呼叫站点 . 请记住,“下一件事要做" was "只是为了给list-iter-cc
的来电者返回一个值”?然后使用列表中的下一个值重新输入外部let
的正文 .这需要转换为宏,然后应该是直截了当的 .
我注意到你的教授在那里使用了命名循环,宏调用
(loop ((cdr a)))
. 虽然延续不返回其值,因此由于调用loop
而未输入loop
的下一次迭代 . 控件跳转作为延续的一部分,如我的示例函数中所示(当我在DrRacket中测试时,它可以工作) .更新:关于你的成绩单,
head2
已经#<continuation>
,它没有car
- 它不是pair?
. 相反,请参阅以下内容:什么?你看到刚刚发生了什么吗?
head
重新定义了!然后再次,为什么?因为运行延续意味着控件返回到其调用站点 - 这里,这意味着“定义变量
head
以保存提供的值,并返回到REPL” .