转换为CPS(续传样式)

时间:2012-02-02 13:11:38

标签: scheme continuation-passing

如何将Scheme中的这些程序转换为CPS表格?

  1. (lambda (x y)
      ((x x) y))
    
  2. (lambda (x)
      (lambda (f)
        (f (lambda (y)
             (((x x) f) y))))
    
  3. ((lambda (x) (x x)
     (lambda (x) (x x))
    
  4. *这不是任何作业!

2 个答案:

答案 0 :(得分:24)

请参阅第{15页},从第15章开始。第18章讨论如何自动完成,但如果你不熟悉表达一个“下一步该做什么”的功能,那么你将会可能想先尝试手指练习。

不要有人为你做这件事:你真的想要了解这个过程,并且能够独立于Scheme或其他方式手工完成。它特别出现在异步JavaScript Web编程中,你真的别无选择,只能进行转换。


在CPS变换中,所有非原始函数现在都需要使用表示“下一步做什么”的函数。这包括所有的lambdas。对称地,非原始函数的任何应用程序都需要提供“下一步做什么”函数,并将其余的计算填充到该函数中。

所以,如果我们有一个程序来计算三角形的hypothenuse:

(define (hypo a b)
  (define (square x) (* x x))
  (define (add x y) (+ x y))

  (sqrt (add (square a)
             (square b))))

如果我们声明这里唯一的原始应用程序是*+sqrt,则需要翻译所有其他函数定义和函数调用,如下所示:

(define (hypo/k a b k)
  (define (square/k x k)
    (k (* x x)))

  (define (add/k x y k)
    (k (+ x y)))

  (square/k a 
            (lambda (a^2)
              (square/k b
                       (lambda (b^2)
                         (add/k a^2 b^2
                                (lambda (a^2+b^2)
                                  (k (sqrt a^2+b^2)))))))))

;; a small test of the function.
(hypo/k 2 3 (lambda (result) (display result) (newline)))

最后一个表达式显示你最终必须计算“由内而外”,并且转换是普遍存在的:原始源程序中的所有lambdas最终需要采用额外的参数,并且所有非原始应用程序都需要把这个论点称为“接下来做什么”。

仔细阅读所引用书籍的第17.2节:它涵盖了这一点以及17.5,其中讨论了为什么需要触摸源程序中的所有lambdas,以便更高阶的情况也适用。


作为转换的另一个例子,应用于更高阶的情况,假设我们有:

(define (twice f)
  (lambda (x) 
    (f (f x))))

然后这样的翻译是:

(define (twice/k f k1)
  (k1 (lambda ...)))

...因为lambda只是一个可以传递给k1的值。但当然,翻译也需要贯穿lambda。

我们必须首先使用fx进行内部调用(并记住所有非原始函数应用程序需要传递适当的“下一步做什么!”):< / p>

(define (twice/k f k1)
  (k1 (lambda (x k2)
        (f x (lambda (fx-val)
               ...)))))

...取出该值并再次应用于f ...

(define (twice/k f k1)
  (k1 (lambda (x k2)
        (f x (lambda (fx-val)
               (f fx-val ...))))))

...最后将该值返回k2

(define (twice/k f k1)
  (k1 (lambda (x k2)
        (f x (lambda (fx-val)
               (f fx-val k2))))))

;; test.  Essentially, ((twice square) 7)
(define (square/k x k) (k (* x x)))
(twice/k square/k 
         (lambda (squaresquare)
           (squaresquare 7
                         (lambda (seven^4) 
                           (display seven^4)
                           (newline)))))

答案 1 :(得分:0)

您需要选择您需要/想要进行CPS转换的级别。

如果你只想要(lambda (x y) ((x x) y))继续传递(CP)风格,那么(lambda (k x y) (k ((x x) y)))就可以了。

如果您希望其参数也被视为CP风格,那么您还需要更多。

首先假设只有第二个参数(y)处于CP形式,因此实际上类似于(lambda (k) (k y0)),因此需要通过一些延续来调用以提取其值,然后您需要:

(lambda (k x y)
  (y (lambda (y0) (k ((x x) y0)) )) )

最后假设xy都是CP风格。然后你需要这样的东西:

(lambda (k x y)
  (x (lambda (x0)
       (x (lambda (x1)
            (y (lambda (y0)
                 (k ((x0 x1) y0)) ))))

您可以自由地重新排序对xy的来电。或者你可能只需要调用x,因为你知道它的值不依赖于调用它的延续。例如:

(lambda (k x y)
  (y (lambda (y0)
       (x (lambda (x0)
            (k ((x0 x0) y0)) ))))

您询问的其他表达方式可以进行类似的转换。