简体   繁体   English

折叠和折叠的长度

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM