2016-11-11 78 views
3

validation包的文档:AccValidation为什么没有Monad实例?

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

作为这个Applicative实例的结果,没有相应的BindMonad实例。 AccValidation就是一个例子,“一个不是单子的应用函子”。

这并不明显,为什么这是一个后果。我可以想象一个Monad实例为AccValidation,其行为如同Either - 什么会使这种非法?

+0

你想象什么情况?请注意,'Either'的应用实例在非错误端进行累加。 – Alec

+2

如果早期阶段失败,则不能在稍后的“阶段”中运行。使用Applicative,即使您不能将它们应用于获得成功的结果(因此您可以知道后面的阶段的计算是否失败),您仍然可以*计算*后面的阶段。随着Monad,每个阶段都会返回下一个阶段,所以你甚至不知道后面的阶段应该是什么。 – immibis

+0

@Alec适用于'Either'并不会“积累”*在所有方面*与AccValidation积累的意义相同,对吗? –

回答

4

机械,为AccValidationEither -ish Monad例如将

-- 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 

打破的<*> = ap单子法律。

直观上,它不能成为单子,因为在单子中,计算的效果(即验证失败)可能取决于先前的约束结果。但在失败的情况下,没有结果。所以Either在这种情况下没有其他选择,只能在短路故障,因为没有什么东西可以提供给后面的功能在右边的(>>=) s。

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

+0

不是'ap'只是'<*>'的别名''像'fmap/<$>''? – notgiorgi

+1

@notgiorgi不完全。 ['ap'是'(<*>)'使用'Monad'方法实现的](https://hackage.haskell.org/package/base-4.9.1.0/docs/src/GHC.Base.html#ap)。 'ap'就是'(<*>)''liftM'到'fmap'的地方。 – duplode

5

The (<*>) = ap exigence可以明确的术语来表示的(>>=)

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

现在,鉴于FunctorApplicative实例为AccValidation,我们有:

fmap _ (AccFailure e) = AccFailure e -- [2] 

AccFailure e1 <*> AccFailure e2 = AccFailure (e1 <> e2) -- [3] 

如果我们u = AccFailure e1v = AccFailure e2在[ 1],我们得到:

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

代[2]和[3]成导致我们:

AccFailure (e1 <> e2) = AccFailure e1 >>= \_ -> AccFailure e2 -- [4] 

的问题是,它是不可能写一个(>>=)使得[4]成立。左侧取决于e2值,必须在应用\_ -> AccFailure e2 :: Semigroup e => a -> AccValidation e b时在右侧产生。但是,没有什么可以应用的 - 特别是,e1的类型错误。 (关于这一点的进一步讨论,请参阅仙人掌答案的最后两段。)因此,没有办法给予与其Applicative之一一致的实例AccValidationa。

相关问题