我正在尝试使用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的新手,仍在努力解决所有问题。)
答案 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)给出相同结果的唯一方法是,如果b
和z 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 = ....