我目前正在阅读wikibooks中的Alternative/MonadPlus类型类。它很好地描述了差异。但是,令人费解的是guard
函数,我假设该函数用于“短路”计算。 (我对吗?)
尽管在guard
中定义了函数Control.Monad
,但它具有Alternative
约束,如下所示(link)。
guard :: (Alternative f) => Bool -> f ()
guard True = pure ()
guard False = empty
但是上面的文章提到只需要
MonadPlus
来执行左零和右零定律(因此,要求更严格)。mzero >>= f = mzero -- left zero
m >> mzero = mzero -- right zero
鉴于
guard
函数的用途,难道不应该使用MonadPlus
约束对其进行定义吗?如果guard
应该“短路”计算,我们是否不需要更严格的定律?我对特定设计选择背后的原因感到好奇。附注:除了“短路”一词外,我不知道有什么更好的方式来描述“取消前期计算”行为?
最佳答案
guard
具有Applicative
约束,因为您不需要对其执行单子(monad)运算来定义函数。
它的定义是(从Hackage source复制):
guard :: (Alternative f) => Bool -> f ()
guard True = pure ()
guard False = empty
如果它指定了
MonadPlus
而不是Alternative
,那么它什么也得不到。 MonadPlus
是Alternative
的子类,因此所有MonadPlus
实例都可以使用guard
,但并非所有Alternatives
都可以使用它。(尽管很少有排除
Alternatives
的情况-提到的here两种情况都具有MonadPlus
的实例,即使它们不满足左分配规则。)通常,最好坚持编写函数所需的最低限度限制,即使预期用途更加具体。这样一来,没有什么不应该被排除在外,也没有来自那些类型适合它但不是单子(monad)的人的提示。
巧合的是,Hoogle search results错误地显示了
MonadPlus
限制,尽管如果您单击链接,它是正确的。关于haskell - 为什么 `guard`没有用MonadPlus约束定义?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42037064/