延续传球风格 - 功能构成

时间:2011-03-07 04:32:56

标签: haskell lisp racket function-composition continuation-passing

我正在学习使用Racket的CPS,并且我已经设法编写了这些功能:

;lift a regular single-arg function into CPS
(define (lift/k f)
  (lambda (x k)
    (k (f x))))

;compose two CPS functions
(define (compose/k f g)
  (lambda (x k)
    (g x (lambda (y)
           (f y k)))))

它们似乎正常工作

(define (is-two/k x k)
  (k (= x 2)))
(define is-not-two/k (compose/k (lift/k not) is-two/k))
(is-not-two/k 3 display)
(is-not-two/k 2 display)

#t#f

我想知道这些功能是否仍然是“真正的CPS”。我是否搞砸了“真正的”继续传递这些功能?在CPS中使用函数组合技术是犹太的吗?是鼓励吗?或者它会被视为“妥协”吗?是否有更多的CPS-y方式来做到这一点?

是的我知道我刚问了5个问题,但是他们背后的基本思想(我不确定我理解正确)是一样的。其他Lisps,Haskell,Erlang或其他函数式语言的解释都很好。

1 个答案:

答案 0 :(得分:8)

continuation-passing-style变换可以是部分的,也可以是完整的。您通常使用的系统中某些基元(+, - 等)卡在非cps-land中。幸运的是,CPS可以正常工作。

CPSing中的步骤:

  • 选择哪些功能将是原始的。
  • CPS转换,以便只在尾部位置调用所有非原始函数(包括延续)。

所以,在你的代码中,你的'lift / k'基本上把它的给定函数看作是原始的:注意,lift / k的主体在非尾部位置调用'f'。如果您不想将提升的函数视为基元,则必须明确地重写它。

你的'compose'函数组成了两个CPSed函数,但它本身不在CPS中(也就是说,你假设'compose'是原始的。你可能想要CPS它。注意,因为它只返回一个值这很简单:

;compose two CPS functions
(define (compose/k f g k)
  (k (lambda (x k)
       (g x (lambda (y)
              (f y k))))))