for-each

时间:2017-10-26 15:40:50

标签: foreach scheme continuations callcc

我目前在大学攻读课程计划,在看一些练习时,我遇到了这个问题。 教授还没回答我以前的邮件,因此我有更多机会在这里更快地收到答案。

鉴于此代码

(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的第一次迭代中调用return continuation,返回cons x next-stepx是列表的第一个元素,next-step是一个延续。

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

2)。假设在宏head (list-iter-cc lst)'(1 . #<continuation>)1 car var (car head)并显示,但在循环显示 cdr 之后,2将是延续的汽车!它怎么可能评估为3然后'end然后java.lang.UnsupportedOperationException: Java Runtime Environment (JRE) version 1.8 is not supported by this driver. Use the sqljdbc4.jar class library, which provides support for JDBC 4.0. ,以及为什么在我尝试编写以理解它的代码中不会发生这种情况?

任何帮助都会受到赞赏,特别是可以一步一步指导我的帮助。

1 个答案:

答案 0 :(得分: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的延续以保持当前的延续......这是什么?此时, next-to-do 只是将值返回给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

那么,对于x中的第lst个拳头,会发生什么?

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

被调用。即它设置next-step以立即保存当前延续,并从整个函数list-iter-cc返回

它返回什么?对(x . <next-step>)。并且什么打电话给(next-step)是什么意思?这意味着要返回for-each的正文,它会转到lst中的下一个元素,(如果有的话)。如果没有,则退出for-each的循环体,并且'end > 返回<{1}}函数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的呼叫网站。请记住,&#34; 接下来要做的事情&#34;是&#34;只是为list-iter-cc的来电者返回一个值&#34;?然后使用列表中的下一个值重新输入外部let的正文。

然后需要将其转换为宏,这应该是直截了当的。

我注意到你的教授在那里使用命名循环,宏调用(loop ((cdr a)))。但是,延续不会返回其值,因此,loop的下一次迭代未输入,因为调用了loop 。控件跳转作为延续的一部分,如我的示例函数中所示(当我在DrRacket中测试它时它起作用了。)

更新:关于您的成绩单,head2已经是#<continuation>,它没有car - 它不是pair? 1}}。相反,请参阅以下内容:

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

为什么呢?因为运行延续意味着控件返回其调用站点 - 这里,意味着&#34;定义变量head以保存提供的值,并返回到REPL&#34;