scheme continuation inside a for-each

空扰寡人 提交于 2019-12-02 02:11:56

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".

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!