来自validation
包的文档:
AccValidation
数据类型与Either
同构,但有一个Applicative
的实例在错误方面累积。也就是说,如果遇到两个(或更多)错误,则使用Semigroup
操作附加它们。由于此
Applicative
实例,没有相应的Bind
或Monad
实例。AccValidation
是“不是monad的应用函子”的一个例子。
我不清楚为什么会这样。我可以想象一个Monad
AccValidation
实例,其行为类似于Either
- 什么会使这种行为变得非法?
答案 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
右侧的后续功能。
这与应用仿函数形成鲜明对比,其中效果(在这种情况下,验证失败)不能依赖于其他结果,这就是为什么我们可以在不必提供结果的情况下获得所有验证失败的原因(它们来自哪里? ?)从一个计算到另一个计算。