新的Haskell程序员很快就会去找资源,看看foldr
是如何实现的。好吧,代码过去很简单(不要指望新手了解OldList
或FTP
)。
新代码如何运作?
-- | 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
答案 0 :(得分:11)
我只会在the answer @duplode linked中提及不的部分。
首先,您列出的那些实现是默认方法。每个Foldable
类型都需要提供自己特定版本的至少一个,而列表([]
)提供foldr
,which 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:[])))