为什么AccValidation没有Monad实例?

时间:2016-11-11 01:04:03

标签: haskell monads applicative

来自validation包的文档:

  

AccValidation数据类型与Either同构,但有一个Applicative的实例在错误方面累积。也就是说,如果遇到两个(或更多)错误,则使用Semigroup操作附加它们。

     

由于此Applicative实例,没有相应的BindMonad实例。 AccValidation是“不是monad的应用函子”的一个例子。

我不清楚为什么会这样。我可以想象一个Monad AccValidation实例,其行为类似于Either - 什么会使这种行为变得非法?

2 个答案:

答案 0 :(得分:9)

The (<*>) = ap exigence可以用(>>=)

明确说明
u <*> v = u >>= \f -> fmap f v -- [1]

现在,鉴于Functor的{​​{1}}和Applicative个实例,我们有:

AccValidation

如果我们在[1]中设置fmap _ (AccFailure e) = AccFailure e -- [2] AccFailure e1 <*> AccFailure e2 = AccFailure (e1 <> e2) -- [3] u = AccFailure e1,我们会得到:

v = AccFailure e2

将[2]和[3]替换为导致我们:

AccFailure e1 <*> AccFailure e2 = AccFailure e1 >>= \f -> fmap f (AccFailure e2)

问题是不可能写出[{1}}这样[4]成立。左侧取决于AccFailure (e1 <> e2) = AccFailure e1 >>= \_ -> AccFailure e2 -- [4] 值,该值在右侧必须来自应用(>>=)。但是,没有什么可以应用它 - 特别是e2具有错误的类型。 (有关这一点的进一步讨论,请参阅Cactus的最后两段答案。)因此,无法给\_ -> AccFailure e2 :: Semigroup e => a -> AccValidation e b e1实例提供与其AccValidation一致的实例之一。

答案 1 :(得分:6)

从机制上讲,Either的{​​{1}} - ish Monad实例将

AccValidation

这意味着我们有

-- The (Monoid err) context is not used for anything, 
-- it's just there to satisfy the Applicative super-instance
instance (Monoid err) => Monad (AccValidation err) where
    return = AccSuccess
    AccFailure err >>= f = AccFailure err
    AccSuccess x >>= f = f x

打破了AccFailure err1 <*> AccFailure err2 = AccFailure (err1 <> err2) AccFailure err1 `ap` AccFailure err2 = AccFailure err1 的monad法则。

直观地说,它不能成为monad,因为在monad中,计算的效果(即验证失败)可能取决于先前绑定的结果。但是在失败的情况下,没有结果。所以<*> = ap别无选择,只能在这种情况下短路到失败,因为没有任何内容可以提供给Either右侧的后续功能。

这与应用仿函数形成鲜明对比,其中效果(在这种情况下,验证失败)不能依赖于其他结果,这就是为什么我们可以在不必提供结果的情况下获得所有验证失败的原因(它们来自哪里? ?)从一个计算到另一个计算。