foldr在Haskell中做了什么?

时间:2016-05-01 14:50:52

标签: haskell functional-programming

所以我遇到了Haskell中的foldr函数,从我拿起的函数中,你可以用来计算产品和列表的总和:

foldr f x xs

foldr (*) 1 [1..5] = 120
foldr (+) 0 [1..5] = 15

在x部分添加数字会想要,加上总和或乘以最终产品

foldr实际上做了什么以及为什么有人会使用它而不是内置函数'sum'或'product'等?

2 个答案:

答案 0 :(得分:2)

sumproduct本身是使用foldfoldl而不是foldr定义的,但现在暂且区分这个区别) ,从某种意义上说,当使用这些功能时,你 使用折叠。同样,orandconcat以及更多内容也都使用折叠定义。因此,存在折叠存在的一个原因是:许多标准函数可以使用它们来定义,而不是使用冗余代码。

那么你什么时候直接使用折叠?在做某些事情时,已经没有特定的功能,即当您想要使用+*(或||以外的其他内容组合列表的元素时, &&++)。

假设您有一个单位数字列表,并且您希望"连接"他们分成一个数字:

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 zf替换cons运算符节点,用z替换空列表:

enter image description here

相比之下,foldl f z重新定位表达式树并重新定位计算另一端的零元素:

enter image description here

一些观察结果:

  1. 请注意foldr (:) []保持列表不变:

    foldr (:) [] [1..10] == [1..10]
    
  2. 这是有道理的,因为我们只是用自己替换cons运算符,用空列表替换空列表,因此不会改变任何东西。

    1. 如果我们用其他列表替换空列表,我们应该能够附加两个列表,例如:

      foldr (:) [9,8,7] [1,2,3] == [1,2,3,9,8,7]
      
    2. 可以考虑使用cons运算符将元素添加到列表中:

      (:) :: a -> [a] -> [a]
      
    3. 如果我们将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]
      
      1. Data.Set有一个函数insert,其签名在结构上与(:)的签名相似:

        insert :: Ord a => a -> Set a -> Set a
        
      2. 实际上,我们可以使用foldr

        将列表转换为Set
            import qualified Data.Set as S
        
            foldr S.insert S.empty [1,2,3]
        

        请注意空列表如何替换为空集{ - 1}}。 这是一次构建一个元素的数据结构的惯用方法 - 例如哈希映射,尝试,树木等。