for-each内部的方案延续 [英] scheme continuation inside a for-each
问题描述
我目前正在大学学习一门课程的Scheme,同时看着一些练习,我被这个特定的练习卡住了. 教授尚未回复我以前的邮件,因此我有更多机会在这里更快地收到答复.
给出此代码
(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)))
我必须使用它来编写语法为
(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>)
中, car 是1
并得到显示,但是在遍历其 cdr 之后,var (car head)
将是汽车的延续!
2
然后是3
然后是'end
,为什么在我尝试编写以理解它的代码中没有发生这种情况?
任何帮助将不胜感激,尤其是可以逐步指导我的帮助.
我们可以将其重写为
(define list-iter-cc
(lambda (lst)
(call/cc
(lambda (return)
(for-each
(lambda (x)
(call/cc (lambda (next-step)
(return (cons x next-step)))))
lst)
'end))))
所以它是一个lambda函数,带有一个名为lst
的参数.调用此函数时,照常设置lst
来保存函数调用的实际参数.然后,call/cc
设置名为return
的延续来保存当前的延续...这是什么?此时,下一步要做的只是向list-iter-cc
的调用者返回一个值.
这意味着,调用(return a)
会立即将a
的值返回给list-iter-cc
的调用者,就像函数list-iter-cc
完成了计算一样.
现在
(for-each
(lambda (x)
(call/cc (lambda (next-step)
(return (cons x next-step)))))
lst)
输入
.它为列表lst
中的每个元素调用其lambda参数,因此其名称为x
.
那么,对于lst
中的拳头x
,会发生什么?
(call/cc (lambda (next-step)
(return (cons x next-step))))
被调用. IE.它设置了next-step
来保持 current 的延续,并立即从整个功能list-iter-cc
中返回 !
它返回什么?对(x . <next-step>)
.而什么叫(next-step)
是什么意思?这意味着要返回到for-each
的正文,该正文将继续到lst
中的下一个元素, .如果不是,则退出for-each
的循环体,并从list-iter-cc
函数正常返回
那么,我们怎么使用它呢?例如,像这样:
(define (qq lst)
(let ([a ;; <<= ; control returns here
(list-iter-cc lst)])
(unless (eq? a 'end) ; if it's not past-last-element
(let ([val (car a)]) ; take the actual value
(display val) ; use it
(newline)
((cdr a)))))) ; run the `next-step` continuation
在(cdr a)
中继续执行时,控件将跳回到list-iter-cc
的呼叫站点.还记得下一步要做的事"是只是为了向list-iter-cc
的调用者返回一个值"吗?然后使用列表中的下一个值重新输入let
的外部主体.
然后需要将其转换为宏,这应该很简单.
我注意到您的教授在那里使用了命名循环,宏调用了(loop ((cdr a)))
.但是,连续性不会返回其值,因此,由于调用了loop
,因此不会输入loop
的下一个迭代.控件跳转作为延续的一部分,如我的示例函数所示(当我在DrRacket中对其进行测试时,它起作用了).
更新:关于成绩单,head2
已经是#<continuation>
,没有car
–它不是pair?
.相反,请参见以下内容:
> (define head #| <<= |# (list-iter-cc '(1 2 3 4))) ; control returns here
> head
'(1 . #<continuation>)
> (let ( (var (car head))) (display var)) ; your code
1
> ((cdr head)) ; this is how we run it!
> head
'(2 . #<continuation>)
>
什么?你看到发生了什么事吗? head
重新定义!再来一次,
> ((cdr head))
> head
'(3 . #<continuation>)
>
为什么?因为运行连续意味着控件将返回到其调用站点–. .
I'm currently studying Scheme for a course at my university, while looking at some exercises I got stuck on this particular one. Professor has yet to answer my previous mails therefore I have more chances to receive an answer here faster.
Given this code
(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)))
I have to use it to write the iter
macro whose syntax is
(iter <a variable symbol> in <a list> <code>)
example:
(iter x in '(1 2 3)
(display x)
(newline))
Since I couldn't understand list-iter-cc
i went to see the solution, which i don't understand as well. The solution:
(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)))))))))
To unravel the macro I tried writing the following
> (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>
>
which is exactly what I thought would happen.
list-iter-cc
's return continuation is called at the first iteration of the for-each inside the first lambda, returning with cons x next-step
.
x
is the first element of the list and next-step
is a continuation.
1). what is the content of next-step
? the following iteration of the for-each
? how can it evaluate to 'end
after the last iteration?
2). assuming that in the macro head (list-iter-cc lst)
is '(1 . #<continuation>)
, the car is 1
and it gets displayed, but after looping over its cdr, var (car head)
will be the car of the continuation! how can it possibly evaluate to 2
and then 3
and then 'end
, and why this does not happen in the code I tried writing to understand it?
Any help would be appreciated, especially one that could guide me step by step.
We can re-write it as
(define list-iter-cc
(lambda (lst)
(call/cc
(lambda (return)
(for-each
(lambda (x)
(call/cc (lambda (next-step)
(return (cons x next-step)))))
lst)
'end))))
So it's a lambda function, with a parameter named lst
. When this function is called, lst
is set up to hold the actual argument of the function call, as usual. Then, call/cc
sets up the continuation named return
to hold the current continuation ... which is what? At this point, the next-thing-to-do is just to return a value to the list-iter-cc
's caller.
This means, calling (return a)
will return the value of a
immediately to list-iter-cc
's caller, as if the function list-iter-cc
finished up its calculations.
Now,
(for-each
(lambda (x)
(call/cc (lambda (next-step)
(return (cons x next-step)))))
lst)
is entered. It calls its lambda argument for each element in a list lst
, which consequently gets the name x
.
So, for the very fist x
in a lst
, what happens?
(call/cc (lambda (next-step)
(return (cons x next-step))))
is called. I.e. it sets up next-step
to hold the current continuation and returns from the whole function list-iter-cc
at once!
What does it return? The pair (x . <next-step>)
. And what does it mean to call (next-step)
? It means to return into the body of for-each
, which will proceed to the next element in lst
, if any. If not, the loop body of for-each
is exited, and 'end
is normally returned as last expression's value from the function list-iter-cc
, which thus finishes its calculations!
So, how can we use it? For example, like this:
(define (qq lst)
(let ([a ;; <<= ; control returns here
(list-iter-cc lst)])
(unless (eq? a 'end) ; if it's not past-last-element
(let ([val (car a)]) ; take the actual value
(display val) ; use it
(newline)
((cdr a)))))) ; run the `next-step` continuation
When the continuation in (cdr a)
is run, the control jumps back to list-iter-cc
's call site. Remember, "the next-thing-to-do" was "just to return a value to the list-iter-cc
's caller"? The outer let
's body is then re-entered with the next value from the list.
This needs to be translated to a macro then, which should be straightforward.
I notice your prof used named loop there, and the macro calls (loop ((cdr a)))
. The continuation does not return its value though, and so the next iteration of loop
is not entered because of the call to loop
. The control jumps as part of the continuation, as seen in my sample function (it worked, when I tested it in DrRacket).
update: Regarding your transcript, head2
is already a #<continuation>
, it doesn't have a car
– it is not a pair?
. Instead, see the following:
> (define head #| <<= |# (list-iter-cc '(1 2 3 4))) ; control returns here
> head
'(1 . #<continuation>)
> (let ( (var (car head))) (display var)) ; your code
1
> ((cdr head)) ; this is how we run it!
> head
'(2 . #<continuation>)
>
What? Have you seen what just happened? head
got redefined! And again,
> ((cdr head))
> head
'(3 . #<continuation>)
>
Why? Because running a continuation means the control returns to its call site – which, here, means "define a variable head
to hold the supplied value, and return to the REPL".
这篇关于for-each内部的方案延续的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!