00d*_*ani 80 haskell functional-programming typeclass applicative monoids
标准库的Haskell类型类MonadPlus
,Alternative
以及Monoid
各自提供两种方法具有基本相同的语义:
mzero
,empty
或mempty
.a -> a -> a
,在类型类联接值加在一起:mplus
,<|>
或mappend
.所有这三个都规定了应遵守的法律:
mempty `mappend` x = x
x `mappend` mempty = x
Run Code Online (Sandbox Code Playgroud)
因此,似乎三个类型都提供相同的方法.
(Alternative
也提供some
和many
,但它们的默认定义通常是足够的,所以它们在这个问题上并不太重要.)
所以,我的疑问是:为什么这三个极为相似的类?除了不同的超类限制之外,它们之间是否有任何真正的区别?
Edw*_*ETT 111
MonadPlus
并Monoid
服务于不同的目的.
A Monoid
在一种类型上进行参数化*
.
class Monoid m where
mempty :: m
mappend :: m -> m -> m
Run Code Online (Sandbox Code Playgroud)
所以它可以被几乎任何类型实例化,其中有一个明显的操作符是关联的并且有一个单元.
但是,MonadPlus
不仅指定您具有幺半群结构,而且该结构与Monad
工作方式有关,并且该结构不关心monad中包含的值,这是(部分)由事实指示的这MonadPlus
是一种善意的争论* -> *
.
class Monad m => MonadPlus m where
mzero :: m a
mplus :: m a -> m a -> m a
Run Code Online (Sandbox Code Playgroud)
除了幺半群法律,我们还有两套可能适用的法律MonadPlus
.可悲的是,社区不同意他们应该是什么.
至少我们知道
mzero >>= k = mzero
Run Code Online (Sandbox Code Playgroud)
但还有另外两个竞争扩展,左(sic)分布法
mplus a b >>= k = mplus (a >>= k) (b >>= k)
Run Code Online (Sandbox Code Playgroud)
和左捕法
mplus (return a) b = return a
Run Code Online (Sandbox Code Playgroud)
因此,任何实例都MonadPlus
应该满足这些附加法律中的一个或两个.
那怎么样Alternative
?
Applicative
之后被定义Monad
,并且在逻辑上属于超类Monad
,但很大程度上是由于Haskell 98中设计师的压力不同,甚至Functor
在Monad
2015年之前都不是超类.现在我们终于拥有Applicative
了Monad
GHC 的超类(如果不是但是在语言标准中.)
实际上,Alternative
是Applicative
什么MonadPlus
是Monad
.
对于这些,我们得到
empty <*> m = empty
Run Code Online (Sandbox Code Playgroud)
类似于我们所拥有的,MonadPlus
并且存在类似的分配和捕获属性,其中至少有一个是您应该满足的.
不幸的是,即使是empty <*> m = empty
法律也是如此强烈.例如,它不适用于Backwards!
当我们看看MonadPlus时,空的>> = f =空法几乎被强加给我们.无论如何,空构造中不能有任何"a"来调用该函数f
.
但是,由于Applicative
是没有的超类Monad
和Alternative
是不是一个超类MonadPlus
,我们拉闸分别定义两个实例.
而且,即使Applicative
是超级课程Monad
,你最终还是需要MonadPlus
上课,因为即使我们服从了
empty <*> m = empty
Run Code Online (Sandbox Code Playgroud)
这并不足以证明这一点
empty >>= f = empty
Run Code Online (Sandbox Code Playgroud)
因此声称某事物是一件事,MonadPlus
比宣称事情要强Alternative
.
现在,按照惯例,MonadPlus
并Alternative
对于给定的类型应该一致,但Monoid
可能是完全不同的.
例如MonadPlus
,Alternative
为了Maybe
做明显的事情:
instance MonadPlus Maybe where
mzero = Nothing
mplus (Just a) _ = Just a
mplus _ mb = mb
Run Code Online (Sandbox Code Playgroud)
但Monoid
实例将一个半群提升为一个半群Monoid
.遗憾的是,因为Semigroup
当时在Haskell 98中没有一个类,它通过请求a Monoid
而不是使用它的单位来实现.ಠ_ಠ
instance Monoid a => Monoid (Maybe a) where
mempty = Nothing
mappend (Just a) (Just b) = Just (mappend a b)
mappend Nothing x = x
mappend x Nothing = x
mappend Nothing Nothing = Nothing
Run Code Online (Sandbox Code Playgroud)
TL; DR MonadPlus
是一个更强有力的主张Alternative
,反过来比一个更强的主张Monoid
,而一个类型的MonadPlus
和Alternative
实例应该相关,Monoid
可能(有时是)完全不同的东西.