为什么 `(((call/cc (lambda (k) k)) (lambda (x) x)) “嘿!”)` 评估为“嘿!”?

问题描述 投票:0回答:2

我正在阅读方案编程语言并在后续部分看到这个例子:

(((call/cc (lambda (k) k)) (lambda (x) x)) "HEY!") => "HEY!"

我不明白为什么这个表达式评估为“嘿!”

根据 CSE 341 讲义

(call/cc expr)
执行以下操作:

  1. 捕获当前的延续。
  2. 构造一个带有一个参数的函数
    C
    ,并将当前延续应用到该参数值。
  3. 将此函数作为参数传递给
    expr
    --- 即,它调用
    (expr C)
    .
  4. 返回评估
    (expr C)
    的结果,除非
    expr
    调用
    C
    ,在这种情况下返回传递给
    C
    的值。

所以,在这个例子中

(((call/cc (lambda (k) k)) (lambda (x) x)) "HEY!") => "HEY!"

  1. call/cc
    的当前延续是

    (lambda (v)
       ((v (lambda (x) x)) "HEY!")
    
  2. 构造函数

    C

    (lambda (y)
       ((lambda (v)
           ((v (lambda (x) x)) "HEY!")) y))
    
  3. 调用

    ((lambda (x) x) C)

  4. 返回评估

    ((lambda (x) x) C)
    的结果,也就是
    C
    本身

因此,

(call/cc (lambda (k) k))
的计算结果为
C
。整个表达式将是:

(((lambda (y)
  ((lambda (v)
      ((v (lambda (x) x)) "HEY!")) y)) (lambda (x) x)) "HEY!")

((C (lambda (x) x)) "HEY!")
,也就是
("HEY!" "HEY!")
。 这将导致异常:
Wrong type to apply: "HEY!"
,意味着应用非函数值“嘿!”。

我哪里错了?

functional-programming scheme programming-languages continuations callcc
2个回答
0
投票

我会尝试分解它。

开始
(((call/cc (lambda (k) k)) (lambda (x) x)) "HEY!")

评估

((call/cc (lambda (k) k)) (lambda (x) x))
的结果需要是一个函数,并且用参数
"HEY!"
调用它。

(call/cc (lambda (k) k))

调用一个匿名函数并传递给它一个延续,一个特殊的函数,当被调用时,会将其参数返回到

call/cc
返回的位置。匿名函数只是返回那个延续而不调用它。将该延续称为
kont
,并将其替换为整个
call/cc
表达式:

(kont (lambda (x) x))

现在调用该延续,带有一个匿名函数,该函数接受一个参数并将其作为参数返回。因此,该功能是评估延续的结果。所以基本上

((call/cc (lambda (k) k)) (lambda (x) x))
等同于
(lambda (x) x)
。然后用参数
"HEY!"
调用它,然后它返回。


0
投票

我是这样读的,用CPS表示:

(define (identity& v k)
  (k v))

(define (call/cc& f& k)
  (f& (lambda (v ingnored-k) (k v)) k))

(define (repl-print v)
  v)

(call/cc& identity&
          (lambda (v&)
            (v& identity&
                (lambda (v2&)
                  (v2& "HEY!" repl-print)))))

所以

call/cc&
调用的当前延续是:

(lambda (v&)
  (v& identity&
      (lambda (v2&)
        (v2& "HEY!" repl-print))))
  1. 第一轮,

    v&
    是一个continuation函数,当被调用时,不会将值传递给它自己的continuation(ignored-k),而是
    call/cc&
    的continuation。因此,如果
    v&
    被调用,上面将被调用。

  2. v&
    被调用,结果是
    identity&
    。因此,原始延续被调用,这次
    v&
    identity&

  3. v&
    (
    identity&
    ) 被称为
    identity&
    作为参数和延续
    (lambda (v2&) ...)

  4. v2&
    identity&
    它被称为
    "HEY!"
    和延续
    repl-print

  5. repl-print
    被调用
    "HEY!"
    。显示文本,程序终止。

注意 #1 和 #2 最终以不同的值调用相同的延续。如果它是一样的,你就会有一个循环。

© www.soinside.com 2019 - 2024. All rights reserved.