简体   繁体   English

方案:继续编译

[英]Scheme: Compiling with continuations

im currently writing a compiler in OCaml for a subset of scheme and am having trouble understanding how to compile with continuations.我目前在 OCaml 中为方案的子集编写编译器,并且无法理解如何使用延续进行编译。 I found some great resources, namely:我发现了一些很棒的资源,即:

Using the anormal transformation introduced in the anormal-paper, I now have code where function calls are either bound to a variable or returned.使用 anormal-paper 中介绍的异常转换,我现在有了代码,其中 function 调用要么绑定到变量,要么返回。

Example:例子:

(define (fib n)
  (if (<= n 1)
      n
      (+ (fib (- n 1)) 
         (fib (- n 2)))))

becomes:变成:

(define (fib n)
  (let ([c (<= n 1)])
    (if c
        n
        (let ([n-1 (- n 1)])
          (let ([v0 (fib n-1)])
             (let ([n-2 (- n 2)])
               (let ([v1 (fib n-2)])
                 (+ v0 v1)))))))

In order to cps-transform, I now have to:为了进行 cps 转换,我现在必须:

  1. add cont-parameters to all non-primitive functions为所有非原始函数添加 cont 参数
  2. call the cont-parameter on tail-positions在尾部位置调用 cont 参数
  3. transform all non-primitive function calls, so that they escape the let-binding and become an extra lambda with the previous let-bound variable as sole argument and the previous let-body as the body转换所有非原始 function 调用,使它们逃脱 let-binding 并成为一个额外的 lambda ,之前的 let-bound 变量作为唯一参数,之前的 let-body 作为主体

The result would look like:结果将如下所示:

(define (fib n k)
  (let ([c (<= n 1)])
    (if c
        (k n)
        (let ([n-1 (- n 1)])
          (fib n-1 
            (lambda (v0) 
              (let ([n-2 (- n 2)]) 
                (fib n-2
                  (lambda (v1) 
                    (k (+ v0 v1))))))))))

Is this correct?这个对吗?

The csmu-course also talks about how Programs in CPS require no stack and never return. csmu 课程还讨论了 CPS 中的程序如何不需要堆栈并且永不返回。 Is that because we don't need to to save the adresses to return to and closures as well as other datatypes are stored on the heap and references are kept alive by using the closures?那是因为我们不需要保存要返回的地址,而闭包以及其他数据类型都存储在堆上,并且使用闭包使引用保持活动状态?

The csmu also talks about desugaring of call/cc: csmu 还谈到了 call/cc 的脱糖:

(call/cc) => ((lambda (k f) (f k k)))

when using such desugaring, how does:使用这种脱糖时,如何:

(+ 2 (call/cc (lambda (k) (k 2))))

in MIT-Scheme return 4, since the current continuation would probably be something like display?在 MIT-Scheme 返回 4 中,因为当前的延续可能类似于显示?

is this correct?这个对吗?

(define (fib n k)
  (let ([c (<= n 1)])
    (if c
        (k n)
        (let ([n-1 (- n 1)])
          (fib n-1 
            (lambda (v0) 
              (let ([n-2 (- n 2)]) 
                (fib n-2
                  (lambda (v1) 
                    (k (+ v0 v1))))))))))

you get an A+你得到一个A+


The csmu-course also talks about how Programs in CPS require no stack and never return. csmu 课程还讨论了 CPS 中的程序如何不需要堆栈并且永不返回。 Is that because we don't need to to save the addresses to return to and closures as well as other datatypes are stored on the heap and references are kept alive by using the closures?那是因为我们不需要保存要返回的地址,而闭包以及其他数据类型都存储在堆上,并且通过使用闭包来保持引用保持活动状态?

Exactly!确切地! See Chicken Complilation Process for an in-depth read about such a technique.有关这种技术的深入阅读,请参阅鸡肉编译过程


The csmu also talks about desugaring of call/cc: csmu 还谈到了 call/cc 的脱糖:

 (call/cc) => ((lambda (kf) (fkk)))

That doesn't look quite right.那看起来不太对劲。 Here's a desugar of call/cc from Matt Might -这是来自Matt Mightcall/cc的脱糖 -

call/cc => (lambda (f cc) (f (lambda (x k) (cc x)) cc))

The essence of the idea of compiling with continuations is that you want to put an order on the evaluation of arguments passed to each function and after you evaluate that argument you send its value to the continuation passed.使用延续编译的想法的本质是,您希望对传递给每个 function 的 arguments 的评估下达命令,并在评估该参数后将其值发送给传递的延续。

It is required for the language in which you rewrite the code in CPS form to be tail recursive, otherwise it will stack empty frames, followed only by a return.以 CPS 形式重写代码的语言要求是尾递归的,否则它将堆叠空帧,然后仅返回。 If the implementation language does not impose tail-recursion you need to apply more sophisticated methods to get non-growing stack for cps code.如果实现语言不强制执行尾递归,则需要应用更复杂的方法来获取 cps 代码的非增长堆栈。

Take care, if you do it, you also need to change the signature of the primitives.请注意,如果您这样做,您还需要更改原语的签名。 The primitives will also be passed a continuation but they return immediately the answer in the passed continuation, they do not create other continuations.原语也将传递一个延续,但它们会立即在传递的延续中返回答案,它们不会创建其他延续。

The best reference about understanding how to compile with continuations remains the book of Andrew W. Appel and you need nothing more.关于理解如何使用延续进行编译的最佳参考仍然是 Andrew W. Appel 的书,您不需要更多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM