Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ruby-on-rails-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scheme 呼叫cc示例球拍_Scheme_Racket_Continuations_Callcc - Fatal编程技术网

Scheme 呼叫cc示例球拍

Scheme 呼叫cc示例球拍,scheme,racket,continuations,callcc,Scheme,Racket,Continuations,Callcc,我正在分析有关call/cc使用的代码。这个函数有点神秘,要完全理解它相当复杂 我真的无法理解这个代码是如何工作的。下面是我的解释 (define (print+sub x y) (display x) (display " ") (display y) (display " -> ") (- x y)) (define (puzzle) (call/cc (lambda (exit) (defin

我正在分析有关
call/cc
使用的代码。这个函数有点神秘,要完全理解它相当复杂

我真的无法理解这个代码是如何工作的。下面是我的解释

(define (print+sub x y)
  (display x)
  (display " ")
  (display y)
  (display " -> ")
  (- x y))

(define (puzzle)
  (call/cc (lambda (exit)
             (define (local e)
               (call/cc
                (lambda (local-exit)
                  (exit (print+sub e
                           (call/cc
                            (lambda (new-exit)
                              (set! exit new-exit)
                              (local-exit #f))))))))
             (local 6)
             (exit 2))))

(define x (puzzle))
call/cc
通过

    call/cc (lambda(exit))
然后再次通过

              (call/cc
                (lambda (local-exit)
使用参数
6
调用函数
local
,该参数作为
x
传递到
print+sub
。但是值
2
如何到达
print+sub
作为
y

最重要的是,所有这些指令的执行顺序是什么?

调用
(拼图)
设置一个continuation
exit
,这样调用
(exit val)
就好像调用
(拼图)
刚刚返回了
val
值一样

然后调用
(本地6)
。它设置一个连续的
本地出口
,这样调用
(本地出口val2)
就如同调用
(本地6)
刚刚返回了该
val2
值一样。当然,返回值会被忽略,下一个调用,
(退出2)
将在下一个调用中执行

现在,在设置了
本地出口后
,调用
(出口(打印+sub e…)
)。它需要首先找出
(print+sub e…
val3
值,以便将其传递给调用
(exit val3)

print+sub
需要两个参数。调用中有两个表达式必须求值,因此找到的值(如果有)将作为
x
y
传递到
print+sub

评估
e
很简单。它是
6

计算第二个表达式,
(call/cc(lambda(new exit)…)
,设置另一个延续,
new exit
,这样调用
(new exit y)
相当于将
y
返回到调用中等待它的插槽
{y}

然后是

      (lambda (new-exit)
          (set! exit new-exit)
          (local-exit #f))
输入
(设置!退出新退出)
将任何调用
(退出val)
的含义从现在起更改为与调用
(新退出val)
的含义相同

现在,最后调用
(本地出口#f)
。它跳出
(本地6)
调用,立即返回
#f
,然后被忽略。呼叫
(退出2)
。这与呼叫
(新出口2)
相同。这意味着将
2
返回到
{y}
插槽中,因此现在执行
(打印+子E2)
内部
(退出(打印+子E2))
调用

print+sub
打印它打印的内容并返回
4
,因此现在调用
(退出4)

现在关键的一点是,这里使用的
exit
值是多少?是原来的
退出
继续,还是更改后的
新退出

假设方案标准规定,在任何函数应用程序中,首先计算
(foo a1 a2…an)
foo
,然后以未指定的顺序计算
ai
s,然后将函数值应用于刚刚找到的
n
参数值。这意味着要调用的
exit
是原始
exit
的延续,因此值
4
返回为原始调用的最终值
(谜题)
(这就是DrRacket中真正发生的情况)

假设方案标准没有这样说。然后
exit
现在实际上可能是
newexit
。因此,调用它将导致无限循环。这不是DrRacket中发生的事情

事实上,如果我们用
(lambda(v)(exit v))
替换
退出

代码确实进入了无限循环


延续就像带值的跳转(a
GOTO
)。当我们有一些代码时,比如
。。。。。。(foo)…
使用正常函数
foo
,当对
foo
的求值结束时,返回值将根据那里写的内容在该代码中进一步使用

puzzle
用作
foo
时,评估将进行相同的操作。Scheme试图找出
puzzle
的返回值,以便在周围的代码中进一步使用它

但是
puzzle
会立即调用
call/cc
,所以它会创建这个标记,一个
GOTO
标签,这样当/if/deep-inside
puzzle
调用
(退出42)
时,控件会跳到-转到-那个标记,那个标签,并且
42
被用作返回值

因此,当深入
(谜题)
调用
(42号出口)
时,其效果与调用
(谜题)
刚刚返回
42
作为其周围代码的返回值一样,而没有遍历
谜题
中的所有剩余代码

这就是延续的工作原理。continuation是要跳转到的标记,带有一个值,将在后续代码中使用,就像前一段代码正常返回一样


使用Racket或等效宏,代码可能更容易阅读:

(define-syntax with-current-continuation    ; let/cc
  (syntax-rules ()
    ((_ c a b ...)
     (call/cc (lambda (c) a b ...)))))

(define (puzzle2)
  (let/cc exit  ; --->>--------------->>------------>>-------------.
    (define (local e)                                            ; |
      (let/cc local-exit  ; --->>----------------------------.     |
        (exit (print+sub e                                 ; |     |
                         (let/cc new-exit  ;  -->>----.      |     |
                           (set! exit new-exit)    ;  |      |     |
                           (local-exit #f))        ;  |      |     |
                                          ;; --<<-----*      |     |
                         )))                               ; |     |
                           ;; --<<-----------------<<--------*     |
      )                                                          ; |
    (local 6)                                                    ; |
    (exit 2))                                                    ; |
            ;; --<<---------------<<------------------<<-----------*
  )
(使用当前延续定义语法;let/cc
(语法规则()
((uuC a b…)
(呼叫/抄送(lambda(c)a b…)))
(定义(2)
(让/cc退出;-->-->----------------------->--------------。
(b)定义(本地e)|
(让/cc本地退出;-->-----------------------------------|
(退出(打印+子e;||
(让/抄送新出口;-->-----)|
(设置!退出新的退出);||
(define-syntax with-current-continuation    ; let/cc
  (syntax-rules ()
    ((_ c a b ...)
     (call/cc (lambda (c) a b ...)))))

(define (puzzle2)
  (let/cc exit  ; --->>--------------->>------------>>-------------.
    (define (local e)                                            ; |
      (let/cc local-exit  ; --->>----------------------------.     |
        (exit (print+sub e                                 ; |     |
                         (let/cc new-exit  ;  -->>----.      |     |
                           (set! exit new-exit)    ;  |      |     |
                           (local-exit #f))        ;  |      |     |
                                          ;; --<<-----*      |     |
                         )))                               ; |     |
                           ;; --<<-----------------<<--------*     |
      )                                                          ; |
    (local 6)                                                    ; |
    (exit 2))                                                    ; |
            ;; --<<---------------<<------------------<<-----------*
  )