6

为什么是guard基于Alternative

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

我问是因为guard只使用emptyfrom Alternative。它根本不使用<|>from Alternative。那么,为什么要Alternative首先使用呢?

Alternative我想这是因为's背后有一些未说明的想法empty与我们试图完成的目标完全匹配guard(停止False,继续True)。如果是这种情况,请告诉我这个未说明的想法。

但同时,如果觉得我们只是在忽略<|>. 感觉好像guard没有“完全捕捉”Alternative一切。我希望这是有道理的。更具体地说:他们为什么不发明另一种类型类,称为Stoppable(or Abortable) 并使用它而不是Alternative

4

1 回答 1

8

TL;DR:历史原因。它在 中是这样设想的MonadPlus,后来得到了它的Applicative变体Alternative,没有人提出分裂AlternativeAZeroandAChoice或类似的。


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

guard :: MonadPlus m => Bool -> m ()

这已在 Haskell 98 报告中指定,其中MonadPlus已注明。顺便说一句,Haskell 1.0 根本没有使用 monad。当Applicative最终得到一个超类时MonadAlternative得到一个超类MonadPlus,mzero = emptymplus = (<|>)

好吧,现在我们知道为什么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包含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)

在这里,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 classesMonoid

于 2017-06-22T13:41:48.217 回答