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)))
我必须用它来编写 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
的 return 延续在第一个 lambda 中的 for-each 的第一次迭代中被调用,returning with 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)
将是car的延续!它怎么可能评估为 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
的延续来保存当前延续……这是什么?此时,下一步要做的事情只是return给list-iter-cc
的调用者一个值。
这意味着,调用 (return a)
会将 return 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 延续和 returns 来自整个函数 list-iter-cc
一次!
它是什么return?这对 (x . <next-step>)
。而调用(next-step)
是什么意思?意思是return进入for-each
的正文,lst
,若有,则进入下一个元素。如果不是,则退出 for-each
的循环体,并且 'end
通常 return 作为函数 [=20= 的最后一个表达式的值], 这样就完成了它的计算!
那么,我们该如何使用呢?例如,像这样:
(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)
中的continuation为运行时,控件跳转回list-iter-cc
的调用点。还记得,"the next-thing-to-do" 是 "just to return a value to the list-iter-cc
's caller" 吗?然后使用列表中的下一个值重新输入外部 let
的正文。
这需要转换成一个宏,这应该很简单。
我注意到你的教授在那里使用了 命名循环 ,宏调用 (loop ((cdr a)))
。尽管延续没有 return 它的值,因此 loop
的下一个迭代不会进入 因为调用了 loop
。控件 jumps 作为延续的一部分,如我的示例函数所示(它有效,当我在 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>)
>
为什么?因为 运行ning 一个延续意味着控制 returns 到它的调用站点——在这里,这意味着 "define a variable head
to hold the supplied value, and return to the REPL".
我目前正在我大学的一门课程中学习 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)))
我必须用它来编写 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
的 return 延续在第一个 lambda 中的 for-each 的第一次迭代中被调用,returning with 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)
将是car的延续!它怎么可能评估为 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
的延续来保存当前延续……这是什么?此时,下一步要做的事情只是return给list-iter-cc
的调用者一个值。
这意味着,调用 (return a)
会将 return 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 延续和 returns 来自整个函数 list-iter-cc
一次!
它是什么return?这对 (x . <next-step>)
。而调用(next-step)
是什么意思?意思是return进入for-each
的正文,lst
,若有,则进入下一个元素。如果不是,则退出 for-each
的循环体,并且 'end
通常 return 作为函数 [=20= 的最后一个表达式的值], 这样就完成了它的计算!
那么,我们该如何使用呢?例如,像这样:
(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)
中的continuation为运行时,控件跳转回list-iter-cc
的调用点。还记得,"the next-thing-to-do" 是 "just to return a value to the list-iter-cc
's caller" 吗?然后使用列表中的下一个值重新输入外部 let
的正文。
这需要转换成一个宏,这应该很简单。
我注意到你的教授在那里使用了 命名循环 ,宏调用 (loop ((cdr a)))
。尽管延续没有 return 它的值,因此 loop
的下一个迭代不会进入 因为调用了 loop
。控件 jumps 作为延续的一部分,如我的示例函数所示(它有效,当我在 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>)
>
为什么?因为 运行ning 一个延续意味着控制 returns 到它的调用站点——在这里,这意味着 "define a variable head
to hold the supplied value, and return to the REPL".