不清楚foldl类型的定义

时间:2013-02-08 08:38:57

标签: haskell

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)

2 个答案:

答案 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,因为它只返回最后一次调用折叠函数的结果。