作为一个小练习,我试图重新编码。这段代码似乎有效(除了无限列表):
allComp f acc x = acc && f x
all :: (a -> Bool) -> [a] -> Bool
all f xs = foldl (allComp f) True xs
但如果我保留相同的签名,那么这个就不会编译:
allComp f acc x = acc && f x
all :: (a -> Bool) -> [a] -> Bool
all f xs = foldr (allComp f) True xs
编译错误是:
Couldn't match type `a' with `Bool'
`a' is a rigid type variable bound by
the type signature for all :: (a -> Bool) -> [a] -> Bool
at Main.hs:8:8
Expected type: Bool -> Bool
Actual type: a -> Bool
In the first argument of `allComp', namely `f'
In the first argument of `foldr', namely `(allComp f)'
In the expression: foldr (allComp f) True xs
任何人都可以更清楚地解释为什么第一个版本编译而不是第二版?
答案 0 :(得分:4)
如果您在Hoogle上进行搜索,则会看到foldl
和foldr
的签名不同:
foldl :: (a -> b -> a) -> a -> [b] -> a
foldr :: (a -> b -> b) -> b -> [a] -> b
现在让我们让签名更加语义上:
foldl :: (a -> b -> a) -> a -> [b] -> a
foldr :: (b -> a -> a) -> a -> [b] -> a
您会看到第一个参数(函数)中类型的顺序不同。这是因为foldl
看起来像:
foldl f z [x1,x2,...,xn] = f (f (f (... (f z x1) x2) x3)...) xn
而foldr
看起来像:
foldr f z [x1,x2,...,xn] = f z (f x1 (f x2 (... (f xn-1 xn) ...)))
由于(&&)
是关联的,因此无关紧要。您只需使用flip :: (a -> b -> c) -> b -> a -> c
:
all f xs = foldr (flip (allComp f)) True xs