TL;DR:历史原因。它在 中是这样设想的MonadPlus
,后来得到了它的Applicative
变体Alternative
,没有人提出分裂Alternative
成AZero
andAChoice
或类似的。
Alternative
是一个相对较新的想法,就像Applicative
. 回到guard
最初设想的时候,它是基于MonadPlus
,Monad
应该支持选择和失败的,就像Alternative
. 它的原始类型是这样的
guard :: MonadPlus m => Bool -> m ()
这已在 Haskell 98 报告中指定,其中MonadPlus
已注明。顺便说一句,Haskell 1.0 根本没有使用 monad。当Applicative
最终得到一个超类时Monad
,Alternative
得到一个超类MonadPlus
,mzero = empty
和mplus = (<|>)
。
好吧,现在我们知道为什么guard
使用Alternative
. 因为它是基于MonadPlus
之前的。那么为什么会这样MonadPlus
定义呢?
从 1998 年开始,人们必须给 SPJ 或委员会的其他人写一封邮件才能得到他们的理由,因为仅仅一年后,Erik Meijer 和 Graham Hutton 写了他们的“Haskell 中的单子解析”论文。如果您查看论文,您会注意到它们的 MonadPlus
工作方式与您的预期一样:
class Monad m => MonadZero m where
zero :: m a
class MonadZero m => MonadPlus m where
(++) :: m a -> m a -> m a
因此,当然可以按照您描述的方式处理这种“可停止”。但是,base
目前没有定义empty
没有Alternative
. 可能有一个,但尚未提出。
请注意,这是 Haskell 类中反复出现的主题。Monoid
包含mappend
和mempty
。在其构思之后,有人注意到某些类型mappend
是有意义的,但不是mempty
。例如
newtype Min a = Min a
combine :: Ord a => Min a -> Min a -> Min a
combine (Min x) (Min y) = Min (min x y)
在这里,mappend = combine
显然是关联的,而Min
如果我们只使用 ,则不可能为空Ord
,我们将不得不使用Bounded
。这就是为什么 now Semigroup
,它还不是的基类Monoid
,但给了我们关联操作。
回到你原来的问题:guard
使用Alternative
, 因为Alternative
提供empty
,并empty
“停止”在某些Alternative
's 的评估。还没有其他类包含它。
但是有一个提案,可能会在某个时候出现,尽管我不确定社区对拆分的看法Alternative
是什么。
顺便说一句,像 PureScript 之类的语言会拆分Alternative
,尽管它们是反过来拆分的……</p>
有关我用作另一个示例的更多信息Alternative
以及我为什么使用它,请参阅Confused by the meaning of the 'Alternative' type class and its relationship to other type classes。Monoid