所以我遇到了Haskell中的foldr函数,从我拿起的函数中,你可以用来计算产品和列表的总和:
foldr f x xs
foldr (*) 1 [1..5] = 120
foldr (+) 0 [1..5] = 15
在x部分添加数字会想要,加上总和或乘以最终产品
foldr实际上做了什么以及为什么有人会使用它而不是内置函数'sum'或'product'等?
答案 0 :(得分:2)
sum
和product
本身是使用fold
(foldl
而不是foldr
定义的,但现在暂且区分这个区别) ,从某种意义上说,当使用这些功能时,你 使用折叠。同样,or
,and
,concat
以及更多内容也都使用折叠定义。因此,存在折叠存在的一个原因是:许多标准函数可以使用它们来定义,而不是使用冗余代码。
那么你什么时候直接使用折叠?在做某些事情时,已经没有特定的功能,即当您想要使用+
或*
(或||
以外的其他内容组合列表的元素时, &&
或++
)。
假设您有一个单位数字列表,并且您希望"连接"他们分成一个数字:
concatDigits = foldl (\acc d -> d + acc * 10) 0
现在concatDigits [1,2,3]
为您提供123
。
或者您已经定义了一些数据结构,并且您希望将列表转换为它:
fromList = foldr insert empty`
事实上,fromList
通常是为许多数据结构定义的。
答案 1 :(得分:0)
Wikipedia entry很好地说明了foldr
对列表的作用以及它与foldl
的区别。
列表[1,2,3]
由cons运算符(:)
生成,空列表[]
由此表达式树生成:
:
/ \
1 :
/ \
2 :
/ \
3 []
foldr f z
用f
替换cons运算符节点,用z
替换空列表:
相比之下,foldl f z
重新定位表达式树并重新定位计算另一端的零元素:
一些观察结果:
请注意foldr (:) []
保持列表不变:
foldr (:) [] [1..10] == [1..10]
这是有道理的,因为我们只是用自己替换cons运算符,用空列表替换空列表,因此不会改变任何东西。
如果我们用其他列表替换空列表,我们应该能够附加两个列表,例如:
foldr (:) [9,8,7] [1,2,3] == [1,2,3,9,8,7]
可以考虑使用cons运算符将元素添加到列表中:
(:) :: a -> [a] -> [a]
如果我们将f
定义为:
f :: Int -> [Int] -> [Int]
f a as = [0] ++ [a] ++ as
然后foldr f []
将在输入列表的每个元素之前添加0:
foldr f [] [1,2,3] == [0,1,0,2,0,3]
Data.Set
有一个函数insert
,其签名在结构上与(:)
的签名相似:
insert :: Ord a => a -> Set a -> Set a
实际上,我们可以使用foldr
import qualified Data.Set as S
foldr S.insert S.empty [1,2,3]
请注意空列表如何替换为空集{ - 1}}。 这是一次构建一个元素的数据结构的惯用方法 - 例如哈希映射,尝试,树木等。