【问题标题】:Foldr/Foldl for free when Tree is implementing Foldable foldMap?当 Tree 实现 Foldable foldMap 时,Foldr/Foldl 是免费的吗?
【发布时间】:2014-06-12 17:39:51
【问题描述】:

我是 Haskell 的初学者,正在学习“Learn You a Haskell”。

关于FoldableTree 实现,我有些不明白。

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  

来自 LYAH 的引述:“因此,如果我们只为某种类型实现 foldMap 我们会在该类型上免费获得 foldrfoldl!” .

有人能解释一下吗?我不明白我现在如何以及为什么免费获得foldrfoldl...

【问题讨论】:

  • 顺便说一句,提供这些免费实现的机制类似于/= 的免费实现,如果你实现==,就像讨论的here 一样

标签: haskell fold foldable


【解决方案1】:

我们从foldMap的类型开始:

foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m

foldMap 的工作原理是将 a -> m 函数映射到数据结构上,然后通过它运行将元素粉碎成单个累积值与 mappend

接下来,我们注意到,给定某个类型bb -> b 函数形成一个幺半群,(.) 作为其二元运算(即mappend)和id 作为标识元素(即@ 987654332@。如果你还没有遇到,id 定义为id x = x)。如果我们将 foldMap 专门化为那个幺半群,我们会得到以下类型:

foldEndo :: Foldable t => (a -> (b -> b)) -> t a -> (b -> b)

(我将函数称为foldEndo,因为内函数是从一种类型到相同类型的函数。)

现在,如果我们查看列表的签名foldr

foldr :: (a -> b -> b) -> b -> [a] -> b

我们可以看到 foldEndo 匹配它,除了泛化到任何 Foldable 和一些参数的重新排序。

在我们开始实现之前,有一个技术难题是b -> b 不能直接成为Monoid 的实例。为了解决这个问题,我们使用来自Data.MonoidEndo newtype 包装器:

newtype Endo a = Endo { appEndo :: a -> a }

instance Monoid (Endo a) where
        mempty = Endo id
        Endo f `mappend` Endo g = Endo (f . g)

写成EndofoldEndo只是专门的foldMap

foldEndo :: Foldable t => (a -> Endo b) -> t a -> Endo b

所以我们直接跳转到foldr,用foldMap来定义。

foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
foldr f z t = appEndo (foldMap (Endo . f) t) z

这是默认定义you can find in Data.Foldable。最棘手的可能是Endo . f;如果您对此有疑问,请不要将f 视为二元运算符,而是将其视为a -> (b -> b) 类型的一个参数的函数;然后我们用 Endo 包装生成的 endofunction。

至于foldl,推导本质上是相同的,只是我们使用不同的内函数幺半群,flip (.)作为二元运算(即我们以相反的方向组合函数)。

【讨论】:

    【解决方案2】:

    foldr 总是可以定义为:

    foldr f z t = appEndo (foldMap (Endo . f) t) z
    

    其中 appEndo 和 Endo 只是新类型的解包器/包装器。事实上,这段代码是直接从 Foldable 类型类中提取的。所以,通过定义 foldMap,你会自动得到 foldr。

    【讨论】:

    • 类似地,foldl 可以定义为foldr,因此也可以定义为foldMap,所以这个功能也是免费的。
    猜你喜欢
    • 1970-01-01
    • 2016-09-04
    • 2021-06-05
    • 1970-01-01
    • 1970-01-01
    • 2010-09-27
    • 2011-08-28
    • 2015-01-08
    • 1970-01-01
    相关资源
    最近更新 更多