【问题标题】:Execute the following call/cc expression执行以下 call/cc 表达式
【发布时间】:2016-03-21 19:48:21
【问题描述】:

我使用球拍,我得到了4的结果,下面的简单代码:

(let/cc done
  ((let/cc esc
     (done (+ 1 (let/cc k
                  (esc k)))))
   3))

我打算一步一步地执行这段代码。

首先,我将第一个 let/cc 更改为 call/cc 的形式,如下所示:

(call/cc (λ (done)
           ((let/cc esc
              (done (+ 1 (let/cc k
                           (esc k)))))
            3)))

当然,这也会产生4

其次,因为我在internet 中找到了call/cc 的机制,上面写着call/cc,请执行以下4 个步骤:

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

因此,我对第一个call/cc 遵循了上述步骤,例如:

  1. 当前的延续是一种身份。
  2. C 指的是(λ (x) x)
  3. 由于expr(λ (done) ((let/cc esc (done (+ 1 (let/cc k (esc k))))) 3))(expr C) 是:

    ((λ (done)
       ((let/cc esc
          (done (+ 1 (let/cc k
                       (esc k)))))
        3))
     (λ (x) x))
    
  4. 为了返回上面代码的结果值,我在racket中执行了上面。

但是,上面的代码(由我修改)没有执行并产生错误:

> application: not a procedure;
>
> expected a procedure that can be applied to arguments
>
>  given: 4
>
>  arguments...:
>
>   3

请问我做错了什么。我混淆了延续的概念。谢谢。

【问题讨论】:

    标签: scheme racket evaluation continuations callcc


    【解决方案1】:

    延续不仅仅是闭包(函数)。他们还执行跳转到他们在代码中的定义位置。您必须完全执行 CPS 转换才能尝试在 Scheme 解释器中评估结果表达式。该表达式将仅包含 lambdas 并且没有延续(在 call/cc (1) 的意义上)。

    您尝试的表达式将它们混合在一起 - 它将 done 定义为简单的 lambda 定义的函数,但它仍然在嵌套上下文中用作延续。


    (1)(另一个混淆的来源是调用函数参数的延续传递风格“延续”。他们是不是 “真正的”延续;它们是在这种或那种可能性中“被调用”的简单函数,因此通俗地说它们也被称为“延续”,尽管“意外事件”甚至“处理程序”可能更好。)

    另见another example of call/cc code translation

    按照这种方法,将您的 Scheme 代码翻译成 Common Lisp,我们得到:

    ;; (let/cc done
    ;;   ((let/cc esc
    ;;      (done (+ 1 (let/cc k
    ;;                   (esc k)))))
    ;;    3)) 
    (prog  (retval done arg1 func esc arg2 k arg3 arg4)
        (setq done (lambda (x) (setq retval x) (go DONE)))    ; 3
         (setq arg1 3)                                        ; 5
          (setq esc  (lambda (x) (setq func x) (go ESC)))     ; 8
           (setq arg3 1)                                      ; 10
            (setq k  (lambda (x) (setq arg4 x) (go K)))       ; 12
            (setq arg4 (funcall esc k))                       ; 13
      K                                                       ; 11  continuation K
           (setq arg2 (+ arg3 arg4))                          ; 9
          (setq func (funcall done arg2))                     ; 7
      ESC                                                     ; 6   continuation ESC
         (setq retval (funcall func arg1))                    ; 4
      DONE                                                    ; 2   continuation DONE
        (return retval))                                      ; 1
    

    确实是returns 4(在翻译过程中,代码行按编写顺序编号)。

    【讨论】:

      【解决方案2】:

      当解释器看到call/cc 时,即使是不执行 CPS 的解释器也会使用该子树进行处理。您的代码将如下所示:

      ((λ (done)
         ((λ (esc)      
            ((λ (k) (esc k))
             (λ (r) (k+ done 1 r))))
          (λ (v) (v 3))))
       values)
      
      
      ; k+ implementation (+, but CPS) 
      (define (k+ k . args)
        (k (apply + args)))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-15
        • 2011-08-25
        • 2020-04-10
        • 2015-04-13
        • 1970-01-01
        • 2020-02-01
        • 1970-01-01
        • 2011-02-16
        相关资源
        最近更新 更多