MonadPlus
和 Monoid
的作用不同。
Monoid
是针对 *
类型的参数化。
class Monoid m where
mempty :: m
mappend :: m -> m -> m
因此,它可以被实例化为几乎任何具有明显的可结合运算符和单位元素的类型。
然而,MonadPlus
不仅指定了您拥有一种单调结构,而且该结构与 Monad
的工作方式相关,并且该结构不关心单调体中包含的值,这在一定程度上表现为 MonadPlus
接受了一个 * -> *
类型的参数。
class Monad m => MonadPlus m where
mzero :: m a
mplus :: m a -> m a -> m a
除了幺半律,我们还可以应用两个潜在的法则集到MonadPlus
上。遗憾的是,社区对它们应该是什么有不同意见。
至少我们知道
mzero >>= k = mzero
但是还有另外两个竞争的扩展,左 (sic) 分布律。
mplus a b >>= k = mplus (a >>= k) (b >>= k)
左侧捕获法则
mplus (return a) b = return a
因此,任何一个MonadPlus
实例都应该遵守这两个额外的法则中的一个或两个。
那么Alternative
呢?
Applicative
是在Monad
之后定义的,逻辑上属于Monad
的超类,但由于Haskell 98设计者面临的不同压力,直到2015年连Functor
都不是Monad
的超类。现在我们终于在GHC中将Applicative
作为Monad
的超类(如果还没有成为语言标准的话)。
从本质上讲,Alternative
对于Applicative
的作用就像MonadPlus
对于Monad
的作用一样。
对于这些,我们会得到
empty <*> m = empty
类似于我们在
MonadPlus
中拥有的内容,存在类似的分配和捕获属性,其中至少需要满足一个条件。
不幸的是,即使是 empty <*> m = empty
定律也太强了。例如,在 Backwards 中,这个定律就不成立!
当我们看 MonadPlus 时,empty >>= f = empty
定律几乎被强制执行。空构造中不能有任何 'a' 值来调用函数 f
。
然而,由于 Applicative
不是 Monad
的超类,Alternative
也不是 MonadPlus
的超类,因此我们最终将分别定义这两个实例。
此外,即使 Applicative
是 Monad
的超类,你仍然需要使用 MonadPlus
类,因为即使我们遵守了
empty <*> m = empty
这并不完全足以证明那个。
empty >>= f = empty
声称某个东西是MonadPlus
比声称它是Alternative
更强大。
现在,按照惯例,给定类型的MonadPlus
和Alternative
应该是一致的,但是Monoid
可能会是完全不同的。
例如,对于Maybe
,MonadPlus
和Alternative
做了很明显的事情:
instance MonadPlus Maybe where
mzero = Nothing
mplus (Just a) _ = Just a
mplus _ mb = mb
但是Monoid
实例将一个半群提升到一个Monoid
。可悲的是,因为在Haskell 98中没有存在一个Semigroup
类,所以它通过要求一个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
总结:MonadPlus
比Alternative
更强,而Alternative
又比Monoid
更强。虽然一个类型的MonadPlus
和Alternative
实例应该是相关的,但Monoid
可能是(有时是)完全不同的东西。
Applicative
和MonadPlus
看起来完全相同(除了超类约束)。 - PeterArrowZero
和ArrowPlus
用于箭头。我的猜测是:使类型签名更清晰(这使得不同的超类约束成为真正的差异)。 - Cat Plus PlusArrowZero
和ArrowPlus
的种类为* -> * -> *
,这意味着您可以将它们一次传递给需要多种类型使用它们的函数的箭头类型。要使用Monoid
,您必须为每个特定实例要求Monoid
实例,并且不能保证它们以类似的方式处理,这些实例可能是不相关的!” - Edward Kmett