阅读“真实世界Haskell”,第95页,作者提供了一个例子:
myFoldl f z xs = foldr step id xs z
where step x g a = g (f a x)
我的问题是:为什么这段代码会编译? foldr
只需要三个参数 - 但在这里,它会传递四个:step
,id
,xs
,z
。
例如,这不起作用(因为sum需要一个):
sum filter odd [1,2,3]
相反,我必须写:
sum $ filter odd [1,2,3]
答案 0 :(得分:12)
以下是foldr
的类型:
Prelude> :t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
我们可以弄清楚它是如何成为四参数函数的吗?我们试一试吧!
我们将id :: d -> d
作为第二个参数(b
),所以让我们将其替换为类型:
(a -> (d -> d) -> (d -> d)) -> (d -> d) -> [a] -> (d -> d)
在Haskell中,a -> a -> a
与a -> (a -> a)
相同,后者给我们(删除最后一组括号):
(a -> (d -> d) -> (d -> d)) -> (d -> d) -> [a] -> d -> d
让我们通过将e
替换为(a -> (d -> d) -> (d -> d))
而将f
替换为(d -> d
来简化,以便更容易理解:
e -> f -> [a] -> d -> d
所以我们可以清楚地看到我们已经构建了一个四参数函数!我的头疼。
这是一个从n-arg函数创建n + 1参数函数的简单示例:
Prelude> :t id
id :: a -> a
id
是一个参数的函数。
Prelude> id id id id id 5
5
但我只给了5个args!
答案 1 :(得分:10)
这是因为多态foldr
是多少:
foldr :: (a -> b -> b) -> b -> [a] -> b
在这里,我们已将b
实例化为函数类型,我们将其称为c -> c
,因此foldr
的类型专门用于(例如)
foldr :: (a -> (c -> c) -> (c -> c)) -> (c -> c) -> [a] -> c -> c
答案 2 :(得分:9)
foldr
只需要3个参数
错误。 Haskell中的所有函数都只取1个参数,并产生1个结果。
foldr :: (a -> b -> b) -> b -> [a] -> b
请参阅foldr
接受一个参数(a -> b -> b)
,并生成1个结果:b -> [a] -> b
。当你看到这个:
foldr step id xs z
请记住,这只是简写:
((((foldr step) id) xs) z)
这解释了为什么这是无稽之谈:
sum filter odd [1,2,3]
(((sum filter) odd) [1,2,3])
sum :: Num a => [a] -> a
以列表作为输入,但是你给了它一个函数。