问题描述
为什么 guard
基于 Alternative
?
guard :: Alternative f => Bool -> f ()
-- guard b is pure () if b is True,
-- and empty if b is False.
我问是因为 guard
仅使用 Alternative
中的 empty
.它根本不使用 Alternative
中的< |>
.那么,为什么要首先使用 Alternative
?
I ask because guard
only uses the empty
from Alternative
. It doesn't use <|>
from Alternative
at all. So why bother using Alternative
in the first place?
我猜这是因为 Alternative
的 empty
背后有一些未阐明的想法,与我们正在尝试使用 guard 完成的任务完全匹配代码>(在
False
上停止,在 True
上继续).如果是这种情况,请向我介绍这个未阐明的想法.
I guess this is because there is some unstated idea behind Alternative
's empty
that matches perfectly with what we're trying to accomplish with guard
(stop on False
, continue on True
). If this is the case, please enlighten me about this unstated idea.
同时,如果感觉到我们只是忽略了< |>
.感觉好像 guard
并没有完全捕获" Alternative
的全部含义.我希望这是有道理的.更具体地说:他们为什么不发明另一个类型类,称为 Stoppable
(或 Abortable
),并使用它代替 Alternative
?
Yet at the same time, if feels that we're just ignoring <|>
. It feels almost as if guard
is not "fully capturing" what Alternative
is all about. I hope that makes sense. To make it more concrete: Why didn't they invent another type class called something like Stoppable
(or Abortable
) and used that instead of Alternative
?
推荐答案
TL; DR:历史原因.在 MonadPlus
中对此进行了设想,后来又得到了 Applicative
变体 Alternative
,并且没有人建议拆分 Alternative 代码>到
AZero
和 AChoice
或类似的代码中.
TL;DR: Historical reasons. It was envisioned like this in MonadPlus
, which got its Applicative
variant Alternative
later, and no one has proposed to split Alternative
into AZero
and AChoice
or similar.
Alternative
是一个相对的新概念.回到最初设想 guard
时,它是基于 MonadPlus
,应该支持选择和失败的 Monad
,就像 Alternative
一样.因此其原始类型为
Alternative
is a relatively new idea, just like Applicative
. Back when guard
was first envisioned, it was based on MonadPlus
, a Monad
that should support choice and failure, just like Alternative
. Its original type was thus
guard :: MonadPlus m => Bool -> m ()
这是在Haskell 98报告中指定的,其中 MonadPlus
一个>已经被注意到.顺便说一下,Haskell 1.0根本不使用monad.当 Applicative
最终获得 Monad
的超类时, Alternative
得到 MonadPlus
的超类,并且 mzero =空
和 mplus =(< |>)
.
That was specified in the Haskell 98 report, where MonadPlus
was already noted. Haskell 1.0 didn't use monads at all, by the way. When Applicative
finally got a superclass of Monad
, Alternative
got a superclass of MonadPlus
, and mzero = empty
and mplus = (<|>)
.
好吧,现在我们知道为什么 guard
使用 Alternative
了.因为它事先基于 MonadPlus
.那么为什么要这样定义 MonadPlus
?
Well, now we know why guard
uses Alternative
. Because it was based on MonadPlus
beforehand. So why is MonadPlus
defined like this?
一个人必须写一封信给SPJ或委员会的其他人,以获取1998年的依据,因为仅仅一年后,埃里克·迈耶(Erik Meijer)和格雷厄姆·赫顿(Graham Hutton)撰写了他们的在Haskell中进行Monadic解析" 论文.如果您看一下这篇论文,您会发现他们的 MonadPlus
的工作原理与您预期的一样:
One would have to write a mail to SPJ or someone else from the committee to get their rationale from 1998, because just one year later, Erik Meijer and Graham Hutton wrote their "Monadic Parsing in Haskell" paper. If you have a look at the paper, you'll notice that their MonadPlus
just works like you intend:
class Monad m => MonadZero m where
zero :: m a
class MonadZero m => MonadPlus m where
(++) :: m a -> m a -> m a
因此,一定可以用您描述的方式来处理可停止的"事件.但是,根本没有 base
类当前没有 Alternative
的情况下定义了 empty
的类.可能有一个,但尚未提出.
So it's certainly possible to handle this "stoppable" the way you've described it. However, there is simply no base
class that currently defines empty
without Alternative
. There could be one, but it wasn't proposed yet.
请注意,这是Haskell类的重复主题. Monoid
包含 mappend
和 mempty
.在构思之后,有人注意到,在某些类型中, mappend
是有意义的,而对于 mempty
则没有意义.例如
Note that this is a recurring theme with Haskell classes. Monoid
contains mappend
and mempty
. After its conception, someone noticed that there are certain types where mappend
makes sense, but not mempty
. For example
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
显然是关联的,而如果仅使用 Ord
,则不可能有空的 Min
使用 Bounded
.这就是为什么现在有 Semigroup
,它不是 Monoid
的基类,但是为我们提供了关联操作.
Here, mappend = combine
is clearly associative, whereas an empty Min
isn't possible if we just use Ord
, we would have to use Bounded
. That's why there is now Semigroup
, which isn't a base class of Monoid
yet, but gives us that associative operation.
回到您最初的问题: guard
使用 Alternative
,因为 Alternative
提供了 empty
和 empty
在某些 Alternative
中停止"评估.没有其他包含 的类.
To come back to your original question: guard
uses Alternative
, because Alternative
provides empty
, and empty
"stops" the evaluation in certain Alternative
's. There's no other class that contains that, yet.
但是有一个建议,也许会在某个时候出现,尽管我不确定社区对拆分 Alternative
的看法是什么.
But with a proposal, there might be at some point, although I'm not sure what's the community's opinion on splitting Alternative
is.
顺便说一下,像PureScript这样的语言会拆分 Alternative
,尽管它们是将其拆分的另一种方式……
By the way, languages like PureScript split Alternative
, although they split it the other way round…
有关 Alternative
以及为什么使用 Monoid
作为另一个示例的更多信息,请参见.
For more information about Alternative
and why I used Monoid
as another example, see Confused by the meaning of the 'Alternative' type class and its relationship to other type classes.
这篇关于为什么守卫基于替代?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!