首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >调用/抄送是如何处理从"Lisp in Pieces“到CPS的转换的?

调用/抄送是如何处理从"Lisp in Pieces“到CPS的转换的?
EN

Stack Overflow用户
提问于 2019-09-03 21:24:55
回答 1查看 321关注 0票数 2

图书Lisp的小部分演示了从Scheme到延续传递风格的转换(第5.9.1章,对于那些能够访问这本书的人来说)。转换表示由lambda窗体进行的延续,而call/cc被认为是等效于一个简单的(lambda (k f) (f k k))

我不明白这是如何工作的,因为函数的应用和延续之间没有区别。

下面是从应用程序以外的所有内容中删除的转换版本(完整版本可以在这个要旨中找到):

代码语言:javascript
复制
(define (cps e)
  (if (pair? e)
      (case (car e)
        ; ...
        (else (cps-application e)))
      (lambda (k) (k `,e))))

(define (cps-application e)
  (lambda (k)
    ((cps-terms e)
     (lambda (t*)
       (let ((d (gensym)))
         `(,(car t*) (lambda (,d) ,(k d))
                     . ,(cdr t*)))))))

(define (cps-terms e*)
  (if (pair? e*)
      (lambda (k)
        ((cps (car e*))
         (lambda (a)
           ((cps-terms (cdr e*))
            (lambda (a*)
              (k (cons a a*)))))))
      (lambda (k) (k '()))))

现在考虑来自维基百科的CPS示例

代码语言:javascript
复制
(define (f return)
  (return 2)
  3)

上面的转换将把函数体(return 2)中的应用程序转换为类似于(return (lambda (g13) ...) 2)的东西。延续作为第一个参数传递,值2作为第二个参数传递。如果return是一个普通的函数,这将是很好的。然而,return应该是一个延续,它只需要一个参数。

我看不出这两块是怎么拼在一起的。转换如何将连续表示为lambda表单,而不特别考虑它们的应用?

EN

回答 1

Stack Overflow用户

发布于 2019-09-03 21:43:50

我不明白这是如何工作的,因为函数的应用和延续之间没有区别。

在没有CPS的情况下实现连续需要虚拟机级的方法,例如使用“意大利面堆栈”:在堆分配的帧中分配受垃圾收集影响的词法变量。捕获一个延续就意味着获得一个环境指针,它引用了意大利面堆栈中的一个词法框架。

CPS通过闭包构建一个事实上的意大利面堆栈。闭包将词法绑定捕获到具有无限生存期的对象中。在CPS下,所有闭包都捕获隐藏变量k。该k在意大利面堆栈中充当父帧指针的角色;它将闭包链接在一起。

因为整个程序是一致的CPS转换,所以到处都有一个k参数,它指向一个动态链接的封闭环境链,相当于一个可以恢复执行的事实上的堆栈。

拼图中缺少的一个部分是CPS依赖于尾调用。尾调用确保我们没有使用真正的堆栈;所有有趣的东西都在关闭的环境中。

(然而,即使是尾部呼叫也不是严格要求的,正如亨利·贝克( Henry )在“鸡计划”中所体现的那样,它教会了我们。我们的CPS转换代码可以使用使用堆栈的真正调用,但永远不会返回。每隔一段时间,我们就可以将可访问的环境帧(和所有偶然对象)从堆栈移到堆中,并将堆栈指针倒转。)

现在考虑维基百科中的CPS示例:

啊,但这不是CPS的例子;这是一个应用程序代码的例子,它使用了通过call/cc可以获得的延续。

如果我们手动将它转换为CPS,或者使用机械的编译器,它就变成了CPS。

然而,返回应该是一个延续,它只需要一个参数。

因此,返回只使用一个参数,因为我们正在查看尚未被CPS转换的应用程序源代码。

应用程序级的连续使用一个参数。

CPS-实现级的延续将有隐藏的k参数,就像所有函数一样。

K参数类似于一段机器上下文,如堆栈或帧指针。当使用传统语言并调用print("hello")时,您不会问,为什么只有一个论点?print不需要接收堆栈指针以便知道参数在哪里吗?当然,在编译print时,编译后的代码可以将上下文从一个函数传递到另一个函数,对于高级语言来说是不可见的。

对于方案中的CPS,很容易混淆,因为源语言和目标语言都是Scheme。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57778919

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档