如何将Scheme中的这些程序转换为CPS表格?
(lambda (x y)
((x x) y))
(lambda (x)
(lambda (f)
(f (lambda (y)
(((x x) f) y))))
((lambda (x) (x x)
(lambda (x) (x x))
*这不是任何作业!
答案 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。
我们必须首先使用f
对x
进行内部调用(并记住所有非原始函数应用程序需要传递适当的“下一步做什么!”):< / 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)) )) )
最后假设x
和y
都是CP风格。然后你需要这样的东西:
(lambda (k x y)
(x (lambda (x0)
(x (lambda (x1)
(y (lambda (y0)
(k ((x0 x1) y0)) ))))
您可以自由地重新排序对x
和y
的来电。或者你可能只需要调用x
,因为你知道它的值不依赖于调用它的延续。例如:
(lambda (k x y)
(y (lambda (y0)
(x (lambda (x0)
(k ((x0 x0) y0)) ))))
您询问的其他表达方式可以进行类似的转换。