[英]Length with foldl and foldr
I have two functions computing the length of a list of integers 我有两个函数来计算整数列表的长度
lengthFoldl :: [Int] -> Int
lengthFoldl xs = (foldl (\_ y -> y+1) 0 xs)
and 和
lengthFold :: [a] -> Int
lengthFold xs = foldr (\_ y -> y+1) 0 xs
they are the same except one uses foldr and one foldl. 它们是相同的,除了一个使用foldr和一个foldl。
But when trying to compute the length of any list [1 .. n]
I get a wrong result (one too big) from lengthFoldl. 但是当试图计算任何列表[1 .. n]
的长度时,我从lengthFoldl得到一个错误的结果(一个太大)。
To complement joelfischerr's answer, I'd like to point out that a hint is given by the types of your functions. 为了补充joelfischerr的答案,我想指出一下提示是由你的函数类型给出的。
lengthFoldl :: [Int] -> Int
lengthFold :: [a] -> Int
Why are they different? 他们为什么不同? I guess you might had to change the first one to take an [Int]
since with [a]
it did not compile. 我猜你可能不得不改变第一个采用[Int]
因为[a]
它没有编译。 This is however a big warning sign! 然而这是一个很大的警示标志!
If it is indeed computing the length, why should lengthFoldl
care about what is the type of the list elements? 如果确实在计算长度,为什么lengthFoldl
应该关心列表元素的类型是什么? Why do we need the elements to be Int
s? 为什么我们需要元素为Int
? There is only one possible explanation for Int
being needed: looking at the code 对于需要Int
只有一种可能的解释:查看代码
lengthFoldl xs = foldl (\_ y -> y+1) 0 xs
we can see that the only numeric variable here is y
. 我们可以看到这里唯一的数字变量是y
。 If y
is forced to be a number, and list elements are also forced to be numbers, it seems as if y
is taken to be a list element! 如果强制y
是一个数字,并且列表元素也被强制为数字,似乎y
被视为一个列表元素!
And indeed that is the case: foldl
passes to the function the accumulator first, the list element second, unlike foldr
. 事实确实如此: foldl
首先将累加器传递给函数,将list元素传递给第二个,与foldr
不同。
The general thumb rule is: when type and code do not agree, one should think carefully about which one is right. 一般的拇指规则是:当类型和代码不一致时,应该仔细考虑哪一个是正确的。 I'd say that most Haskellers would think that, in most cases, it is easier to get the type right than the code right. 我会说大多数Haskellers会认为,在大多数情况下,比正确的代码更容易获得正确的类型。 So, one should not just adapt the type to the code to force it to compile: a type error can instead witness a bug in the code. 因此,不应该只是将类型调整为代码以强制它进行编译:类型错误可以反而见证代码中的错误。
Looking at the type definitions of foldl and foldr it becomes clear what the issue is. 查看foldl和foldr的类型定义,可以清楚地看到问题所在。
:t foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
and 和
:t foldl
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
One can see that the foldr takes the item of the list and the second argument into the function and foldl takes the second argument and the item of the list into the function. 可以看到,foldr将列表项和第二个参数放入函数中,foldl将第二个参数和列表项放入函数中。
Changing lengthFoldl
to this solves the problem 将lengthFoldl
更改lengthFoldl
可以解决问题
lengthFoldl :: [Int] -> Int
lengthFoldl xs = foldl (\y _ -> y+1) 0 xs
Edit: Using foldl
instead of foldl'
is a bad idea: https://wiki.haskell.org/Foldr_Foldl_Foldl ' 编辑:使用foldl
而不是foldl'
是一个坏主意: https : //wiki.haskell.org/Foldr_Foldl_Foldl '
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.