Haskell 类型foldMap::(幺半群m)=>;(a->;m)>;f a->;我的意思是,如何实施它?

Haskell 类型foldMap::(幺半群m)=>;(a->;m)>;f a->;我的意思是,如何实施它?,haskell,foldable,Haskell,Foldable,有人能解释一下类型的含义以及如何实现吗 class Foldable f where foldMap :: (Monoid m) => (a -> m) -> f a -> m 基于, 他们将其解释为“将结构的每个元素映射到一个幺半群,并结合结果。”但我不太明白它的意思。如何将元素映射到幺半群的结构 我试过了 foldMap f=mconcat。()f 但我有一个错误: • Couldn't match type ‘f’ with ‘[]’ ‘f’ i

有人能解释一下类型的含义以及如何实现吗

class Foldable f where
  foldMap :: (Monoid m) => (a -> m) -> f a -> m
基于, 他们将其解释为“将结构的每个元素映射到一个幺半群,并结合结果。”但我不太明白它的意思。如何将元素映射到幺半群的结构

我试过了
foldMap f=mconcat。()f
但我有一个错误:

 • Couldn't match type ‘f’ with ‘[]’
      ‘f’ is a rigid type variable bound by
        the class declaration for ‘Foldable’
        at traversable.hs:41:16
      Expected type: f a -> m
        Actual type: [a] -> m
    • In the expression: mconcat . (<$>) f
      In an equation for ‘foldMap’: foldMap f = mconcat . (<$>) f
    • Relevant bindings include
        foldMap :: (a -> m) -> f a -> m (bound at traversable.hs:45:3)
error:
    • Could not deduce (Data.Foldable.Foldable f)
        arising from a use of ‘foldr’
      from the context: Foldable f
        bound by the class declaration for ‘Foldable’
        at traversable.hs:41:7-14
      or from: Monoid m
        bound by the type signature for:
                   foldMap :: forall m a. Monoid m => (a -> m) -> f a -> m
        at traversable.hs:42:14-47
      Possible fix:
        add (Data.Foldable.Foldable f) to the context of
          the type signature for:
            foldMap :: forall m a. Monoid m => (a -> m) -> f a -> m
          or the class declaration for ‘Foldable’
    • In the expression: foldr (\ x -> mappend (f x)) mempty
      In an equation for ‘foldMap’:
          foldMap f = foldr (\ x -> mappend (f x)) mempty
他们将其解释为“将结构的每个元素映射到一个幺半群,并结合结果。”但我不太明白它的意思。如何将元素映射到幺半群的结构

我们使用签名为
a->m
的函数来实现这一点。所以我们自己定义“映射”函数

A是一种代数结构。它本质上是一个三元组,⊕, s0)其中S是一组值,⊕ :: S×S&右箭头;S是一个关联的二元运算符,s0是一个恒等元素,因此s0⊕ s=s ⊕ s0=s

作为的成员的类型是可以“折叠”的数据结构。这意味着,例如,如果您有一个包含
Int
s的
树,那么就有一个
树Int
,这样,对于函数
f::Int->Int->Int
,以及一个中性元素
z
,您就可以派生一个
Int

通过使用
foldMap
我们将对这些元素调用函数
f::a->m
,并使用monoid函数⊕ 要“折叠”这些值。因此,对于实现
Functor
的数据结构,它或多或少相当于
foldMap f=foldr mappend mempty。fmap f

但是,我们可以在
foldr
函数中使用
f
,如:

foldMap' :: (Foldable f, Monoid m) => (a -> m) -> f a -> m
foldMap' f x = foldr (\y -> mappend (f y)) mempty x
或更短:

foldMap' :: (Foldable f, Monoid m) => (a -> m) -> f a -> m
foldMap' f = foldr (mappend . f) mempty

因此,我们首先用
f
对数据结构中的值进行预处理,将其转换为一个monoid对象,并将
mappend
称为这些项的折叠函数。

因此您有以下签名:
foldMap::(monoidm,Foldable f)=>(a->m)->fa m
。让我们一步一步走

制约因素:
Monoid
是可以通过某种操作组合的数据。如果你想一想,你可以得到很多例子。我只想在此提及:

  • Integer
    作为数据,
    +
    作为操作。元素
    1
    2
    可以组合为
    3=1+2
  • Integer
    作为数据,
    *
    作为操作。元素
    1
    2
    可以组合在一起,给出
    2=1*2
  • 列为数据,
    ++
    列为操作。元素
    [1,2]
    [2,3]
    可以组合为
    [1,2,2,3]=[1,2]+[2,3]
  • 大小为2的
    向量
    作为数据,大小为
    +
    作为操作。元素
    可以组合为
    =+
  • 等等
以上所有示例都有一个haskell中的
幺半群
表示,通常使用
newtype
数据
关键字来定义。在haskell中,幺半群运算表示为

一个重要的性质是幺半群有一个中性元素并且是结合的。在
+
下的
整数
上下文中,中性元素是
0
一个关联性由
(a+b)+c=a+(b+c)
这一事实给出。您可以在所有给定的示例中轻松找到这些属性。试试看

可折叠
约束更容易。本质上,您可以将可折叠的数据结构汇总为一个值

函数参数 代码值千言万语,所以

foldMap :: (Monoid m, Foldable f) => (a -> m) -> f a -> m
--          ^^^^^^^^^^^^^^^^^^^^     ^^^^^^^     ^^^
--          |- We've seen this       |           |
--                                   |           |- A 'Set' of a's which can be collapse into a single value
--                                   |- A function to convert a's into a monoid

因此,根据定义,您可以很容易地遵循以下推理/算法:

前提

  • 我有一个元素结构,可以折叠成一个值
  • 我有办法把这个元素转换成幺半群的元素
  • 幺半群有一个中性元素
  • 两个幺半群元素可以组合在一起
  • 算法

    • 通过使用幺半群算子组合结构的元素来折叠它们
    • 如果结构为空,则使用中性元素作为结果
    很别致,但是。。。我还是不明白 问题是,当您定义一个可折叠的实例时,您还没有定义如何折叠结构,每个实例的折叠方式都不同!。正如威廉的回答一样,你可以用
    foldr
    来定义
    foldMap
    ,这意味着
    foldr
    定义了你可以折叠结构的方式。反之亦然:你可以用
    foldMap
    来定义
    foldr
    ,很可能这就是答案!!如果尚未定义
    foldr
    ,则没有实现
    foldMap
    的通用方法,这将取决于您的数据结构。因此,作为一个代码集:

    class Foldable t where
      foldMap :: Monoid m => (a -> m) -> t a -> m -- A default instance can be provided if you define foldr (a.k.a a way to collapse the structure)
      foldr   :: (a -> b -> b) -> b -> t a -> b  -- A default instance can be provided if you define foldMap (a.k.a a way to collapse the structure into a monoid element)
      -- but if you don't provide at least one, It'll be impossible to implement any
      -- because you aren't telling me how to collapse the structure!!
    

    使用功能
    a->m
    。这有时只是一个
    id
    。您可以在这里将
    foldMap f
    实现为
    foldr(\x->mappend(f x))mempty
    。请注意,
    Foldable
    并不意味着
    函子
    @WillemVanOnsem我尝试了,但我得到了错误(在我的帖子中编辑)。您忘记在签名中添加
    Foldable
    类型约束。非常简洁的解释,感谢您包含foldr的定义