Chr*_*tin 7 monads haskell applicative
从validation包的文档:
的
AccValidation数据类型是同构的Either,但有一个实例的Applicative,关于错误侧积聚.也就是说,如果遇到两个(或更多)错误,则使用Semigroup操作附加它们.作为该
Applicative实例的结果,没有对应Bind或Monad实例.AccValidation是一个"不是monad的应用函子"的例子.
我不清楚为什么会这样.我可以想象一个Monad例子的AccValidation行为就像Either- 什么会使这个非法?
该(<*>) = apexigence可以明确的条款规定(>>=):
u <*> v = u >>= \f -> fmap f v -- [1]
Run Code Online (Sandbox Code Playgroud)
现在,考虑到Functor和Applicative实例AccValidation,我们有:
fmap _ (AccFailure e) = AccFailure e -- [2]
AccFailure e1 <*> AccFailure e2 = AccFailure (e1 <> e2) -- [3]
Run Code Online (Sandbox Code Playgroud)
如果我们u = AccFailure e1和v = AccFailure e2[1],我们得到:
AccFailure e1 <*> AccFailure e2 = AccFailure e1 >>= \f -> fmap f (AccFailure e2)
Run Code Online (Sandbox Code Playgroud)
将[2]和[3]代入其中会导致我们:
AccFailure (e1 <> e2) = AccFailure e1 >>= \_ -> AccFailure e2 -- [4]
Run Code Online (Sandbox Code Playgroud)
问题是不可能写出(>>=)[4]成立的东西.左侧取决于在e2右侧必须来自应用的值\_ -> AccFailure e2 :: Semigroup e => a -> AccValidation e b.但是,没有什么可以应用它 - 特别是e1有错误的类型.(有关这一点的进一步讨论,请参阅Cactus答案的最后两段.)因此,没有办法给出AccValidation一个Monad与其一致的实例Applicative.
机械地,Either-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
Run Code Online (Sandbox Code Playgroud)
这意味着我们有
AccFailure err1 <*> AccFailure err2 = AccFailure (err1 <> err2)
AccFailure err1 `ap` AccFailure err2 = AccFailure err1
Run Code Online (Sandbox Code Playgroud)
打破了monad法则<*> = ap.
直观地说,它不能成为monad,因为在monad中,计算的效果(即验证失败)可能取决于先前绑定的结果.但是在失败的情况下,没有结果.因此Either,在这种情况下,除了短路到故障之外别无选择,因为没有任何东西可以用于(>>=)s的右侧的后续功能.
这与应用仿函数形成鲜明对比,其中效果(在这种情况下,验证失败)不能依赖于其他结果,这就是为什么我们可以获得所有验证失败而不必提供结果(它们来自哪里?)来自一个计算到另一个.