我想看看这两个函数的区别:
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
的情况下,我们需要对++
做一些技巧。