【问题标题】:Does Haskell have an eager version of `foldr`?Haskell 是否有一个热切的 `foldr` 版本?
【发布时间】:2020-03-17 12:05:50
【问题描述】:

Foldr Foldl Foldl' wiki 页面描述了foldrfoldl 之间的区别。两个进程都从左到右列出,但foldr 从右到左累积结果,而foldl 从左到右累积结果。

该页面继续不鼓励使用foldl,而支持使用更高效的渴望版本foldl'

foldr 是否有对应的 Eager 版本,大概称为 foldr'?如果是这样,是否有理由在 wiki 页面上没有提及它?

【问题讨论】:

    标签: haskell functional-programming lazy-evaluation fold


    【解决方案1】:

    不需要foldr',因为人们总是可以使用foldr f严格 f 来实现相同的目标。

    我们可以定义它...

    foldr' f a xs = foldr f' a xs
      where f' x y = seq x (seq y (f x y))
    

    ...但如果需要,在调用点传递严格的f 会更简单。

    【讨论】:

    • 为什么有人要在这里传递严格版本的f?有任何性能优势吗?
    • @n.'pronouns'm。 f 严格遵守 x 可能很有用。严格遵守y 更少。
    • 看起来对y 的严格严格会适得其反。
    【解决方案2】:

    快速的Hoogle search 表明Data.Foldable 中确实定义了一个foldr'

    我认为链接页面上没有提到它的原因是它与那里讨论的堆栈溢出问题无关。在大列表上使用foldr (+) 0 计算总和时,可能发生的堆栈溢出不是运算符(+) 的惰性应用的结果。相反,它的出现是因为右折叠(无论是严格还是惰性)的一个基本特征是运算符的最深层嵌套应用程序出现在列表的末尾。对于像(+) 这样需要评估两个操作数以产生任何结果的运算符,这意味着foldrfoldr' 必须在到达列表末尾之前建立一个O(n) 的延续堆栈(+) 操作员可以开始做“真正的工作”。

    【讨论】:

      【解决方案3】:

      foldrfoldl' 对于列表都非常有用。 foldlfoldr' 通常都不适用于列表。但是现在,这些函数实际上是 Foldable 类的方法,并且它们在某些情况下很有用。举一个极端的例子,考虑一下 snoc 列表:

      data SL a = SL a :> a | Nil
      infixl 5 :>
      
      instance Foldable SL where
        foldMap _ Nil = mempty
        foldMap f (xs :> x) = foldMap f xs <> f x
      
        foldl _ b Nil = b
        foldl f b (xs :> x) = f (foldl f b xs) x
      
        foldr' _ n Nil = n
        foldr' c n (xs :> x) =
          let n' = c x n
          in n' `seq` foldr' c n' xs
      

      对于 snoc 列表,foldlfoldr' 非常有用,而 foldrfoldl' 几乎没用!

      许多Foldable 容器可以很好地利用这四种方法。例如,Data.Set.SetData.Map.Map kData.Sequence.Seq 都可以在任一方向上完美折叠。

      import Data.Sequence (Seq)
      import qualified Data.Sequence as S
      
      toForwardList :: Seq a -> [a]
      toForwardList = foldr (:) []
      
      toReverseList :: Seq a -> [a]
      toReverseList = foldl (flip (:)) []
      

      正向和反向转换同样高效,同样懒惰。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多