Haskell:在Continuation Passing Style中完全定义阶乘的问题

时间:2011-01-23 12:15:08

标签: haskell continuations factorial

我一直试图在一个大blob中强调功能编程,Haskell和Continuation Passing Style,而我的结构化/ OOP背景让我很难过。

根据this我理解以下内容应该是CPS风格中阶乘的正确定义:

factorial n = fact n id where id = \x -> x
    fact 0 cont = cont n
    fact (n+1) cont = fact n * (n + 1)

但我不确定最后的“*(n + 1)”部分 - 这是正确的吗?

1 个答案:

答案 0 :(得分:6)

这不太正确(并且不为我编译);值n+1是正确的,但它没有以完全正确的方式使用。也许您打算使用操作员部分?

factorial n' = fact n' id
 where
  id = \x -> x
  fact 0 cont = cont 1
  fact (n+1) cont = fact n (cont . (* (n+1)))

这与以下

相同(但比以上更钝)
factorial n' = fact n' id
 where
  id = \x -> x
  fact 0 cont = cont 1
  fact (n+1) cont = fact n (\ret -> cont (ret * (n+1)) )

我会在这里改变一些事情。首先,id是标准函数,因此您无需重新定义它。其次,这些示例使用“n + k模式”,在GHC中默认不再提供IIRC。您可以使用普通模式变量代替“n + k模式”。请注意,我使用1作为基本情况;如果你从n开始倒计时,这更容易推理,并且应该在计算中的每一步应用延续函数(你已经从归纳步骤中删除了它)。考虑到这些,你可以写

factorial n' = fact n' id
 where
  fact 0 cont = cont 1
  fact n cont = fact (n-1) (cont . (* n))

我会考虑或多或少地习惯。

编辑:我个人不喜欢n + k模式,但我想我会花一些时间来解释它们。如果您考虑使用基础案例和归纳步骤进行数学归纳,我会发现更容易理解。基本案例是fact 0 ...。然后,您可以从基本步骤继续定义其他值:“对于任何fact n k,请通过此关系确定fact (n+1) k。”这与我对正常模式变量的看法不同,这是自上而下而不是自下而上,但我认为它解释了动机以及为什么有些人喜欢这种风格。

我不喜欢n + k模式的原因仅仅是因为我发现定义更混乱,但是YMMV。