为什么mempty会评估Monoid的内容

时间:2017-03-13 18:17:39

标签: haskell monoids

为什么

(mempty :: String)

工作,但

(mempty :: Maybe Bool)

给我一​​个关于Bool没有Monoid类型类的错误,但为什么它甚至重要,它还包含在Maybe中?

2 个答案:

答案 0 :(得分:6)

对于列表,[a]Monoid no matter what

instance {- no requirements on a here! => -} Monoid [a] where
    ...

所以String是一个幺半群,没有进一步检查Char的属性。但Maybe aonly an instance of Monoid if a is

instance Monoid a => Monoid (Maybe a) where
    ...

因此,Maybe Bool要成为幺半群,我们必须检查Bool是否为幺半群。这完全解释了您的错误消息。

后续问题第一:为什么a需要成为Monoid?这样我们就可以写mappend

    Just m1 `mappend` Just m2 = Just (m1 `mappend` m2)

当然,你真的只需要Semigroup;但这种微妙的差异是无关紧要的,因为Bool也不是Semigroup

后续问题二:为什么不Bool一个Monoid?因为有几个很好的例子,并且不清楚哪个"祝福"作为官方实例。因此,实例附加到newtypeBool;最常见的两个是AnyAll

后续问题三:你有什么选择?您可能希望FirstLast用于保持他们看到的第一个(分别为最后一个)Just的幺半群。还有标准实例和mempty = pure mempty; mappend = liftA2 mappend的实例虽然我不知道这个标准位置。

答案 1 :(得分:4)

这是Monoid instance for Maybe

instance Monoid a => Monoid (Maybe a) where
  mempty = Nothing
  Nothing `mappend` m = m
  m `mappend` Nothing = m
  Just m1 `mappend` Just m2 = Just (m1 `mappend` m2)

它要求基础类型具有Monoid实例,因为它自己的mappend委托给基础类型的实例。请注意,此Monoid约束具有不必要的限制,因为实际上并未使用基础mempty。更合适的做法是Option in Data.SemigroupSemigroupMonoid没有mempty):

-- Paraphrasing the relevant bits of the source.
instance Semigroup a => Semigroup (Maybe a) where
  Nothing <> b       = b
  a       <> Nothing = a
  Just a  <> Just b  = Just (a <> b)

newtype Option a = Option { getOption :: Maybe a }

instance Semigroup a => Semigroup (Option a) where
  Option ma <> Option mb = Option (ma <> mb)

instance Semigroup a => Monoid (Option a) where
  mempty = Option Nothing
  mappend = (<>)

如果您希望Monoid Maybe不关心基础类型,请查看Data.Monoid提供的newtype包装:First(或Alt Maybe)表示左偏的,Last(或Dual (Alt Maybe))表示右偏的。

-- For instance, this is the First monoid:
newtype First a = First { getFirst :: Maybe a }

instance Monoid (First a) where
        mempty = First Nothing
        First Nothing `mappend` r = r
        l `mappend` _             = l
GHCi> import Data.Monoid
GHCi> First Nothing <> First Nothing
First {getFirst = Nothing}
GHCi> First (Just 3) <> First Nothing
First {getFirst = Just 3}
GHCi> First Nothing <> First (Just 3)
First {getFirst = Just 3}
GHCi> First (Just 3) <> First (Just 4)
First {getFirst = Just 3}
GHCi> Last (Just 3) <> Last (Just 4)
Last {getLast = Just 4}
GHCi> Alt (Just 3) <> Alt (Just 4)
Alt {getAlt = Just 3}
GHCi> Dual (Alt (Just 3)) <> Dual (Alt (Just 4))
Dual {getDual = Alt {getAlt = Just 4}}

(顺便说一下,Alt委托memptymappend委托给Alternative Maybe的{​​{1}}实例,这相当于Alec建议{{3} }}。)