在LYAH中,有一段代码看起来像这样。
data Tree a = Empty | Node a (Tree a) (Tree a) deriving (Show, Read, Eq)
instance F.Foldable Tree where
foldMap f Empty = mempty
foldMap f (Node x l r) = F.foldMap f l `mappend`
f x `mappend`
F.foldMap f r
ghci> F.foldl (+) 0 testTree
42
ghci> F.foldl (*) 1 testTree
64800
据我所知,foldMap
属于foldMap :: (Monoid m, Foldable t) => (a -> m) -> t a -> m
类型,但Num a => a
本身不属于Monoid
类型,所以我想知道{{1}是怎么做的实际上在这里工作?由于Foldable.foldl
内部调用了foldMap
,Foldable.foldl
的类型是什么?
答案 0 :(得分:9)
如果您考虑foldr
,其类型为(a -> b -> b) -> b -> t a -> b
,则更容易理解。 “代数”函数的类型为a -> b -> b
,您可以将其视为a -> (b -> b)
- 即:将a
作为输入的函数,并返回b -> b
作为输出。
现在,b -> b
是一个 endomorphism ,它也是一个幺半群,而Data.Monoid
定义了一个类型Endo a
(或者这里,它应该是Endo b
),实际上是Monoid
。
foldr
仅在内部使用Endo
来致电foldMap
:
foldr :: (a -> b -> b) -> b -> t a -> b
foldr f z t = appEndo (foldMap (Endo #. f) t) z
foldl
基本上只是翻转参数,以便做同样的伎俩:
foldl :: (b -> a -> b) -> b -> t a -> b
foldl f z t = appEndo (getDual (foldMap (Dual . Endo . flip f) t)) z
要清楚,我从Haskell源代码中复制了这两个函数实现。如果您转到documentation of Data.Foldable,则可以使用各种链接查看来源。这就是我所做的。