foldl :: (a -> b -> a) -> a -> [b] -> a
foldl step zero (x:xs) = foldl step (step zero x) xs
foldl _ zero [] = zero
我不太明白为什么(a - > b - > a )返回 a ,(a - > b - > a ) - > a - > [b] - > a 返回 a 。我认为应该是这样的:(a - > b - > c ) - > a - > [b] - > C 即可。有人可以根据下面的例子向我解释。谢谢!
foldl (+) 0 (1:2:3:[])
foldl (+) (0 + 1) (2:3:[])
foldl (+) ((0 + 1) + 2) (3:[])
foldl (+) (((0 + 1) + 2) + 3) ([])
foldl (+) (((0 + 1) + 2) + 3)
答案 0 :(得分:14)
a
表示累加器值的类型,b
表示输入中每个元素的类型。 (a -> b -> a)
是一个函数,它接受累加器值,列表中的某个项,并返回一个新的累加器值,该值可以传递给下一步。
初始值的类型必须为a
,以便函数的第一次调用可以接收累加器值。累加器函数必须采用a
并返回a
,以便累加器值可以传递到折叠的每个步骤。折叠的最终值必须是a
,因为这是最终调用fold函数返回的累加器的类型。
(a -> b -> c) -> a -> [b] -> c
不能代表折叠,因为折叠功能不会占用c
。折叠函数的输入和输出必须是相同类型,因此累加器可以传递到下一个折叠步骤。
让我们看一个例子,说明如果fold函数返回c
会发生什么。
f :: Integer -> Integer -> Bool -- this is a valid (a -> b -> c)
f acc n = (acc + n) > 0
假设我们使用的是动态语言,我们尝试使用f
折叠。运行时会发生什么?
foldl f 0 [1] ~ (0 + 1) > 0 == True :: Bool
foldl f 0 [1, 2] ~ ((0 + 1) > 0) + 2) > 0 == error - no instance of (+) for Bool
\_________/ \
| \
Bool + Integer
如果您尝试使用不兼容的类型累积,则可以看到无法进行折叠。
答案 1 :(得分:2)
折叠函数(类型(a -> b -> a)
)的返回类型必须与其第一个输入的类型相同。这是因为,查看(几乎正确的,除了最后一行,不应该有foldl (+)
)评估,您之前调用折叠函数的结果将作为第一个输入传递给下次调用。因此,类型必须匹配。在(a -> b -> c)
中,第一个参数和结果的类型仅匹配a ~ c
(类型相等),但在这种情况下,当a和c相等时,我们也可以将它们称为a。假设折叠函数返回类型为a的东西,整个foldl调用的结果也将是类型a,因为它只返回最后一次调用折叠函数的结果。