使用foldr构造foldl

时间:2019-07-13 15:27:01

标签: haskell

我正在尝试使用foldl创建foldr(这是学习haskell的好方法,而其他的答案似乎很复杂)。

我的解决方案是这样:

myFoldl :: (b -> a -> b) -> [a] -> (b -> b)
myFoldl f = foldr op z
  where
    z = []
    op x xs b = myFoldl f xs (f b x)

但不起作用。我收到一条错误消息:

• Couldn't match type ‘a -> b’ with ‘[a]’
  Expected type: b -> (a -> b) -> a -> b
    Actual type: b -> [a] -> a -> b
• In the first argument of ‘foldr’, namely ‘op’
  In the expression: foldr op z
  In an equation for ‘myFoldl’:
      myFoldl f
        = foldr op z
        where
            z = []
            op x xs b = myFoldl f xs (f x b)

但是对我来说看起来不错。 myFoldl带有一个函数,一个列表以及一些要使用的东西。为什么这不起作用? (haskell的新手,仍在努力解决所有问题。)

1 个答案:

答案 0 :(得分:3)

自从您拥有

myFoldl f = foldr op z

您还必须具有:

myFoldl f xs = foldr op z xs                  -- (**)

根据myFoldl的类型,LHS必须具有b -> b的类型。另一方面,从foldr的类型来看,RHS与z的类型相同,您将其定义为z = [],其列表类型为[c]。因此,此表达式的类型为b -> b,但列表类型为[c],并且这两种类型无法协调。

更大的问题是您的op不应以myFoldl的方式递归定义。折叠的点(无论是左侧还是右侧)是替换显式递归,将递归模式抽象为折叠定义,并通过单步重组操作op x r = ...进行表达,其中r是我们问题的递归子问题的结果,已经由折叠本身为我们计算了。因此,单步重组操作的正确定义不应包含任何递归定义。

太好了,让我尝试将您设置在正确的轨道上。我认为您已经意识到myFoldl的定义递归关系是:

myFoldl f (x:xs) b = myFoldl f xs (f b x)     -- (1a)
myFoldl f []     b = b                        -- (1b)

使用上面的定义(**),您希望将其与foldr的定义的递归关系进行调和:

foldr op z (x:xs) = op x (foldr op z xs)
foldr op z []     = z

我们可以像这样在b上进行抽象提取:

foldr op z (x:xs) b = op x (foldr op z xs) b  -- (2a)
foldr op z []     b = z b                     -- (2b)

请注意,(1b)和(2b)给出相同结果的唯一方法是,如果bz b对于所有b都是相等的。请注意,z是此处的函数,而不是列表!希望您可以立即确定z需要在这里使用什么功能。

要调节(1a)和(2a),您的解决方案是写op x xs b = myFoldl f xs (f b x),但这不是正确的方程式。匹配上面(1a)和(2a)的RHS的正确方程式是:

op x (foldr op z xs) b = myFoldl f xs (f b x)

并使用上方的(**)根据我们的foldr重写左侧的myFoldl,我们得到:

op x (myFoldl f xs) b = myFoldl f xs (f b x)

现在,您能看到单步重组操作op的哪种非递归定义可以满足该方程式吗? (提示:这是一个非常简单的定义。)

op x r              b = ....