为什么`guard`基于`Alternative`?

has*_*lHQ 6 haskell

为什么guard基于Alternative

guard :: Alternative f => Bool -> f ()
-- guard b is pure () if b is True,
-- and empty if b is False.
Run Code Online (Sandbox Code Playgroud)

我问因为guard只使用了empty来自Alternative.它不使用<|>Alternative根本.那么为什么要Alternative首先使用呢?

我想这是因为背后有一些不成文的想法Alternativeempty,与我们正在努力与实现的目标完全吻合guard(停止False,继续True).如果是这种情况,请告诉我这个没有说明的想法.

但与此同时,如果觉得我们只是在忽视<|>.感觉好像guard不是"完全捕捉"到底Alternative是什么.我希望这是有道理的.为了使它更具体:为什么他们不发明另一个类似Stoppable(或Abortable)之类的类型并使用它而不是Alternative

Zet*_*eta 8

TL; DR:历史原因.有人设想这样的MonadPlus,它有它的Applicative变种Alternative以后,也没有人提出分割AlternativeAZeroAChoice或相似.


Alternative是一个相对较新的想法,就像Applicative.回到guard最初设想时,它是基于MonadPlus,一个Monad应该支持选择和失败,就像Alternative.因此它的原始类型

guard :: MonadPlus m => Bool -> m ()
Run Code Online (Sandbox Code Playgroud)

这已经在Haskell 98报告中指出,MonadPlus已经注意到了.顺便说一下,Haskell 1.0根本没有使用monad.当Applicative最后得到一个超类时Monad,Alternative得到了一个超类MonadPlus,mzero = emptymplus = (<|>).

那么,现在我们知道为什么guard用了Alternative.因为它是MonadPlus事先制定的.那么为什么这样MonadPlus定义呢?

人们不得不写一封邮件给SPJ或委员会中的其他人从1998年开始获得他们的理由,因为仅仅一年之后,Erik Meijer和Graham Hutton写了他们的"Haskell中的Monadic Parsing"论文.如果你看一下这篇论文,你会发现它们的 MonadPlus正常工作就像你想要的那样:

class Monad m => MonadZero m where
  zero :: m a

class MonadZero m => MonadPlus m where
  (++) :: m a -> m a -> m a
Run Code Online (Sandbox Code Playgroud)

因此,按照你所描述的方式处理这种"可停止"肯定是可能的.但是,目前没有任何baseempty没有Alternative.可能有一个,但尚未提出.

请注意,这是Haskell类的重复主题.Monoid包含mappendmempty.在受孕之后,有人注意到某些类型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)
Run Code Online (Sandbox Code Playgroud)

在这里,mappend = combine显然是关联的,而Min如果我们只是使用Ord,则无法使用空,我们将不得不使用Bounded.这就是为什么现在Semigroup,它还不是一个基类Monoid,但给了我们联想操作.

回到你原来的问题:guard使用Alternative,因为Alternative提供empty,并empty"停止"某些Alternative人的评价.有包含,没有其他类.

但是有了提案,可能会在某个时候,虽然我不确定社群对分裂的看法Alternative是什么.

顺便说一句,像PureScript这样的语言会分裂Alternative,尽管它们会以相反的方式将它分开......

有关Alternative我用作Monoid另一个示例的更多信息和原因,请参阅"Alternative"类型类的含义及其与其他类型类的关系.