Foldable.foldl如何在Num a =>上工作?一个

时间:2017-09-14 16:00:16

标签: haskell functional-programming

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内部调用了foldMapFoldable.foldl的类型是什么?

1 个答案:

答案 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,则可以使用各种链接查看来源。这就是我所做的。