带有折叠架和折叠架的长度

时间:2018-06-22 09:07:47

标签: haskell fold

我有两个函数来计算整数列表的长度

lengthFoldl :: [Int] -> Int
lengthFoldl xs = (foldl (\_ y -> y+1) 0 xs)

lengthFold :: [a] -> Int
lengthFold xs = foldr (\_ y -> y+1) 0 xs

它们是相同的,除了一个使用文件夹和一个文件夹。

但是当尝试计算任何列表[1 .. n]的长度时,我从lengthFoldl中得到了错误的结果(一个太大)。

2 个答案:

答案 0 :(得分:5)

为补充joelfischerr的回答,我想指出您的函数类型给出了提示。

lengthFoldl :: [Int] -> Int
lengthFold :: [a] -> Int

为什么它们不同?我猜您可能必须更改第一个以使用[Int]的方法,因为使用[a]时它不会编译。但是,这是一个很大的警告信号!

如果确实在计算长度,为什么lengthFoldl关心列表元素的类型是什么?为什么我们需要将元素设为Int?仅需要Int的一种可能解释:查看代码

lengthFoldl xs = foldl (\_ y -> y+1) 0 xs

我们可以看到这里唯一的数字变量是y。如果y被强制为数字,并且列表元素也被强制为数字,则似乎y被视为列表元素!

的确是这样:foldl首先将累加器传递给函数,然后将列表元素传递给函数,与foldr不同。

一般的经验法则是:如果类型和代码不一致,则应仔细考虑哪一种是正确的。我想说大多数Haskellers会认为,在大多数情况下,正确的类型比正确的代码容易。因此,不应该只是将类型与代码相匹配以迫使其进行编译:类型错误可以代替代码中的错误。

答案 1 :(得分:3)

查看foldl和foldr的类型定义,可以清楚地知道问题出在哪里。

:t foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

:t foldl
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b

可以看到,文件夹将列表项和第二个参数带入函数,而文件夹foldl将列表中的第二个参数和列表项带入函数。

更改lengthFoldl即可解决问题

lengthFoldl :: [Int] -> Int
lengthFoldl xs = foldl (\y _ -> y+1) 0 xs

编辑:使用foldl代替foldl'是一个坏主意:https://wiki.haskell.org/Foldr_Foldl_Foldl'