为什么
(mempty :: String)
工作,但
(mempty :: Maybe Bool)
给我一个关于Bool
没有Monoid
类型类的错误,但为什么它甚至重要,它还包含在Maybe中?
答案 0 :(得分:6)
对于列表,[a]
是Monoid
no matter what:
instance {- no requirements on a here! => -} Monoid [a] where
...
所以String
是一个幺半群,没有进一步检查Char
的属性。但Maybe a
是only 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
?因为有几个很好的例子,并且不清楚哪个"祝福"作为官方实例。因此,实例附加到newtype
上Bool
;最常见的两个是Any
和All
。
后续问题三:你有什么选择?您可能希望First
或Last
用于保持他们看到的第一个(分别为最后一个)Just
的幺半群。还有标准实例和mempty = pure mempty; mappend = liftA2 mappend
的实例虽然我不知道这个标准位置。
答案 1 :(得分:4)
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.Semigroup
(Semigroup
是Monoid
没有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
委托mempty
和mappend
委托给Alternative
Maybe
的{{1}}实例,这相当于Alec建议{{3} }}。)