首页 文章

在for-each中的方案延续

提问于
浏览
2

我正在攻读我大学的课程计划,同时看一些练习,我被困在这个特定的课程上 . 教授尚未回复我以前的邮件,因此我有更多机会在这里更快地收到答案 .

鉴于此代码

(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 回答

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

    进入 . 它为列表 lst 中的每个元素调用其lambda参数,因此得到名称 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 通常作为函数 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 的呼叫站点 . 请记住,“下一件事要做" was "只是为了给 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” .

相关问题