【问题标题】:Explain how does new foldr work in Haskell解释新的 foldr 在 Haskell 中是如何工作的
【发布时间】:2015-08-08 16:33:08
【问题描述】:

新的 Haskell 程序员很快就会去源头看看 foldr 是如何实现的。好吧,以前的代码很简单(不要指望新手知道OldListFTP)。

新代码是如何工作的?

-- | Map each element of the structure to a monoid,
-- and combine the results.
foldMap :: Monoid m => (a -> m) -> t a -> m
foldMap f = foldr (mappend . f) mempty

-- | Right-associative fold of a structure.
--
-- @'foldr' f z = 'Prelude.foldr' f z . 'toList'@
foldr :: (a -> b -> b) -> b -> t a -> b
foldr f z t = appEndo (foldMap (Endo #. f) t) z

【问题讨论】:

标签: haskell


【解决方案1】:

我只会提到the answer @duplode linked不是的部分。

首先,您列出的那些实现是默认 方法。每个Foldable 类型都需要提供至少一个 的特定版本,列表([])提供foldrwhich is implemented 几乎一如既往:

foldr k z = go
          where
            go []     = z
            go (y:ys) = y `k` go ys

(为了提高效率,这与 Haskell 报告版本有点不同。)

此外,Foldable 默认值略有变化,因为 duplode 的答案是奇怪的 #. 运算符,在 GHC 的 Data.Foldable 代码内部使用。它基本上是. 的更高效版本,在左侧函数是新类型包装器/解包器函数时才起作用。它是使用新的 newtype 强制机制定义的,并且被优化为基本上什么都没有:

(#.) :: Coercible b c => (b -> c) -> (a -> b) -> (a -> c)
(#.) _f = coerce
{-# INLINE (#.) #-}

【讨论】:

    【解决方案2】:

    我对 foldr 的心智模型遵循以下结构:

    给定一个 a:(b:(c:[])) 形式的列表,将所有“:”替换为给定的 op(第一个参数),然后用给定的初始值替换“[]” 值(第二个参数)。

    伪代码示例:

    foldr (+) 0 [1,2,3,4] = 1 + 2 + 3 + 4 + 0
    

    请记住,[1,2,3,4] 等价于 1:(2:(3:(4:[])))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-06
      • 2017-08-08
      • 2021-10-24
      • 1970-01-01
      相关资源
      最近更新 更多