【问题标题】:cps in "yet another haskell turorial"cps 在“又一个 haskell 教程”中
【发布时间】:2013-07-13 10:23:56
【问题描述】:

我正在通过阅读“Yet Another Haskell Tutorial”这本书来学习 Haskell,但在涉及连续传递样式时遇到了问题。这本书给出了一个cps折叠:

cfold’ f z [] = z
cfold’ f z (x:xs) = f x z (\y -> cfold’ f y xs)

并给出测试结果:

CPS> cfold (+) 0 [1,2,3,4]
10
CPS> cfold (:) [] [1,2,3]
[1,2,3]

但是,当我尝试对此进行测试时,我发现有问题,ghci 给出:

*Main> cfold (+) 0 []

<interactive>:8:7:
    Occurs check: cannot construct the infinite type:
      t10 = (t10 -> t10) -> t10
    Expected type: t10 -> t10 -> (t10 -> t10) -> t10
      Actual type: t10 -> t10 -> t10
    In the first argument of `cfold', namely `(+)'
    In the expression: cfold (+) 0 []
    In an equation for `it': it = cfold (+) 0 []

这对我来说很有意义,所以我将 cps 的定义更改为类似 这个:

cfold f z [] = z
cfold f z (x:xs) = (\y -> cfold f y xs) (f x z)

而且效果很好:

*Main> cfold (+) 0 [1,2,3]
6

所以我的问题来了,这是书中的错误还是我在这里错过的东西?

【问题讨论】:

    标签: haskell


    【解决方案1】:

    我认为这本书没有错误。书中的函数cfold' 采用连续传递样式的函数,因此您传递给cfold' 的函数必须采用3 个参数:累加器、当前列表元素和将结果传递给的延续。

    (+) 只接受两个参数,因为它不是 cps 风格的,所以你不能使用 cfold' 函数。要使用 cfold' 对列表的元素求和,您可以这样写:

    > cfold' (\e acc cont -> cont (acc + e)) 0 [3,2,4]
    9
    

    请注意,lambda 采用 三个 参数:元素、累加器和延续。给定当前计算的结果,延续是一个表示“下一步做什么”的函数。所以通过每次调用延续,你处理下一个元素。

    那么,如果我不调用 continuation,你认为会发生什么?我可以停止以这种方式处理列表,以实现像 takeWhile 这样的东西吗?

    > cfold' (\acc e cont -> if e <= 3 then cont (e : acc) else acc) [] [1,2..]
    [3,2,1]
    

    在这个例子中,当元素大于 3 时我们不调用延续,所以我们停止处理列表。否则,我们将元素添加到累加器中,这就是列表反向出现的原因。如示例所示,这适用于无限列表。

    而且,您还可以编写一个函数,将 any 非 cps 样式的 2-argument 函数转换为 cps 样式:

    toCps2 :: (a -> b -> c) -> (a -> b -> (c -> d) -> d)
    toCps2 f = \a b c -> c (f a b)
    

    此函数只是将应用非 cps 函数的结果传递给延续。您可以使用此函数来实现您的 cfold,它采用一个非 cps 样式的函数来折叠列表:

    cfold :: (a -> b -> c) -> b -> [a] -> c
    cfold f = cfold' (toCps2 f)
    

    使用此功能,您现在可以使用 (+) 折叠您的列表:

    > cfold (+) 0 [3,2,4]
    9
    

    【讨论】:

      【解决方案2】:

      Yet Another Haskell Tutorial中也是cfold

      的定义
      cfold f z l = cfold' (\x t g -> f x (g t)) z l
      

      这个函数cfold正在使用cfold'

      在 WinHugs 环境中它工作正常。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-03-11
        • 1970-01-01
        • 1970-01-01
        • 2012-05-13
        • 2018-01-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多