for-each内部的方案延续 [英] scheme continuation inside a for-each

查看:96
本文介绍了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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆