为什么折叠器 (\ x xs -> x : x : xs) [] 不起作用?



我想看看这两个函数的区别:

dupli = foldl (acc x -> acc ++ [x,x]) []
dupli = foldr ( x xs -> x : x : xs) []

我知道foldl和foldr之间的区别,但对于我看到的关于它如何工作的例子,使用(+),除了求和的方法之外,它看起来是一样的。

为什么选择

dupli = foldr (acc x -> acc ++ [x,x]) []

给出

/workspaces/hask_exercises/exercises/src/Lib.hs:142:27: error:
* Occurs check: cannot construct the infinite type: a ~ [a]
Expected type: [a]
Actual type: [[a]]
* In the expression: acc ++ [x, x]
In the first argument of `foldr', namely
`( acc x -> acc ++ [x, x])'
In the expression: foldr ( acc x -> acc ++ [x, x]) []
* Relevant bindings include
x :: [a] (bound at src/Lib.hs:142:22)
acc :: [[a]] (bound at src/Lib.hs:142:18)
dupli' :: t [[a]] -> [a] (bound at src/Lib.hs:142:1)
|
142 | dupli' = foldr (acc x -> acc ++ [x,x]) []
|                           ^^^^^^^^^^^^

确切地说?

查看类型签名。(注意:为了简单起见,我将这两个都专门用于[],而不是一般的Foldable(

foldl :: (b -> a -> b) -> b -> [a] -> b
foldr :: (a -> b -> b) -> b -> [a] -> b

因此在foldl中;累加器自变量";是折叠函数的第一个自变量,而在foldr中,它是第二个自变量。

你提到(+)(+)是一个左侧和右侧参数具有相同类型的函数,因此您不会注意到差异。具体而言,

(+) :: Num a => a -> a -> a

(:)不同。

(:) :: a -> [a] -> [a]

由于在这两种情况下,您的初始累加器都是[],因此您可以在foldr的情况下使用(:),因为累加器类型[a]是第二个参数,但在foldl的情况下,我们需要对++做一些技巧。

最新更新