3

我目前正在为我的大学的一门课程学习 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的返回延续在第一个 lambda 内的 for-each 的第一次迭代中被调用,返回cons x next-step. x是列表的第一个元素,next-step是一个延续。

1)。内容是next-step什么?的以下迭代for-each?在最后一次迭代之后如何评估'end

2)。假设在宏head (list-iter-cc lst)is'(1 . #<continuation>)中,汽车1并且它被显示,但在循环其cdr之后,var (car head)将是延续的汽车!它怎么可能评估为2and 3then 'end,以及为什么在我尝试编写以理解它的代码中不会发生这种情况?

任何帮助将不胜感激,尤其是可以逐步指导我的帮助。

4

1 回答 1

4

我们可以将其重写为

(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)

被输入。它为列表中的每个元素调用其 lambda 参数lst,从而获得名称x

那么,对于 a 中的第一个拳头xlst会发生什么?

              (call/cc (lambda (next-step)
                         (return (cons x next-step))))

叫做。即它设置next-step为保持当前的延续并立即 从整个函数返回list-iter-cc

它返回什么?对(x . <next-step>)打电话是什么意思(next-step)?这意味着返回到 的主体中,如果有的话for-each,它将继续到 中的下一个元素。如果不是,则退出循环体,并通常作为最后一个表达式的值从 function 返回从而完成其计算!lstfor-each'endlist-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>)
> 

为什么?因为运行延续意味着控件返回到它的调用站点——在这里,这意味着“定义一个变量head来保存提供的值,并返回到 REPL”

于 2017-10-26T16:46:21.173 回答