解释新的foldr如何在Haskell中工作

时间:2015-08-08 16:33:08

标签: haskell

新的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

2 个答案:

答案 0 :(得分:11)

我只会在the answer @duplode linked中提及的部分。

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

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

(就效率而言,与Haskell报告版本略有不同。)

此外,由于duplode的回答是Foldable默认值略有变化,因此在GHC的Data.Foldable代码内部使用了奇怪的#.运算符。当左侧函数是newtype包装器/解包器函数时,它基本上是.的更高效版本,只能 。它是使用新的newtype强制机制定义的,并且基本上没有被优化:

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

答案 1 :(得分:0)

我对文件夹的心理模型遵循以下结构:

  

给出以下形式的列表:(b:(c:[])),将所有“:”替换为给定   op(第一个参数),然后用给定的首字母替换“ []”   值(第二个参数)。

伪代码示例:

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

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