Haskell中的Either和Except在用法上有什么区别?

oro*_*ome 5 error-handling haskell user-input exception-handling

我有一个可以从Haskell中的几个参数创建的类,该类需要对这些参数进行一些复杂的验证。目前我有类似

makeAThingExcept :: String -> String -> ... String -> Except ThingError AThing
makeAThingExcept s1 s2 ... = do
    unless (s1CheckPasses s1) (throwError (BadS1 s1))
    ...

data ThingError = BadS1 String ...

instance Show ThingError where
        show (BadS1 s) = "Bad S1: " ++ s

makeAThing :: String -> String -> ... String -> AThing
makeAThing s1 s2 ... = case runExcept (makeAThingExcept s1 s2 ...) of
        Right thing  -> thing
        Left err -> error (show err)
Run Code Online (Sandbox Code Playgroud)

撇开是否有更好的方法,通过使用更具体的类型,而不是做这个String作为参数makeAThingExcept,有没有理由,更喜欢ExceptEither在这样的情况?Exceptvs 的功能和习语之间有什么区别Either

Nik*_*kov 5

不同之处在于 的实例Alternative。“基本”包不导出任何 for Either,据我所知,因为作者不想引入对任何值的偏见,这本身是因为Either应该是一般的总和类型,并代表可能性错误只是一个特例。然而该“变压器”包的确提供了孤儿实例,其结合到所述Error

Error e => Alternative (Either e)
Run Code Online (Sandbox Code Playgroud)

然而,社区从未接受过类型类或孤儿实例,这就是它现在被弃用的原因。IOW 你可以看它好像Either还没有Alternative.

Except类型确实有一个非孤儿实例,它甚至不会将用户绑定到任何组合类,Monoid而是:

(Monad m, Monoid e) => Alternative (ExceptT e m)
Run Code Online (Sandbox Code Playgroud)

这也是值得注意的是,对于例验证处理和积累所有的错误时,Validation抽象是比较合适的。但是有一个权衡:它不能是一个 monad,但它是一个选择性的(在 applicative 和 monad 之间)和一个替代品。


ber*_*gey 2

Except正如评论中所指出的,在&之间转换很容易Either。运行时表示是相同的,甚至。

我总是会选择使用Either. 它在图书馆中随处可见。我很少见到Except

Except是exceptT的一个特例,您在库中看到它。Reader SomeType (Either e a)如果您发现自己用orIO (Either e a)或编写了很多函数Monad m => m (Either e a),那么您可能需要考虑ExceptT。在此之前不要担心它很好 -Either直到它不再使用之前才​​更容易使用。