如何收集Either Monad中的所有错误消息?

问题描述

我试图用Recordapplicatives验证Either Monad的构造。它工作正常。但是我看不到所有错误消息。由于Right的{​​{1}}路径会忽略它们,因此只有第一个可见。

这是我的代码

Either Monad

我的问题是如何保留和显示所有错误消息。也许和州立单子党在一起?

解决方法

要累积错误,Applicative需要一个不同的Either实例。 Either的这种变体有时称为Validation。关于该实例,至少有两个关于Hackage的库提供了Either的变体:

-- Standard definition
(<*>) :: Either e (a -> b) -> Either e a -> Either e b
Left e <*> _ = Left e
Right _ <*> Left e = Left e
Right f <*> Right x = Right (f x)

-- "Validation" variant
(<*>) :: Monoid e => Either e (a -> b) -> Either e a -> Either e b
Left e <*> Left e' = Left (e <> e')
Left e <*> Right _ = Left e
Right _ <*> Left e = Left e
Right f <*> Right x = Right (f x)

在这个主题上,一个共同的争论点是“ validation”变体是否与Monad的{​​{1}}操作兼容(或者首先是否应该兼容):>

Either

我在上面提到了两个库,因为对此主题有不同的看法(我认为这归结为对传统的平等定义没有达成共识,这本身就是Haskell没有形式语义的症状)。

  • validation 库说不存在兼容的monad实例,因此避免定义一个实例。
  • monad-validate 库认为上述法律符合特定的对等概念,在错误报告的情况下可以做的很好,在这种情况下,应该发生的最坏情况是您报告的错误可能比预期的要少。 (图书馆的文档也包含很多相关的说明。)
,

这是因为Either Applicative实例的工作方式。您可以做的就是将Either包裹在newtype中:

newtype Validation e r = Validation (Either e r) deriving (Eq,Show,Functor)

然后给它另一个Applicative实例:

instance Monoid m => Applicative (Validation m) where
  pure = Validation . pure
  Validation (Left x) <*> Validation (Left y) = Validation (Left (mappend x y))
  Validation f <*> Validation r = Validation (f <*> r)

您现在可以使用<$><*>来组成Validation [Err] Record的结果。有关更多详细信息,请参见我在Applicative validation上的文章。