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

What are the difference in usage between Either and Except in Haskell?

我有一个 class 可以从 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)

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

如评论中所述,ExceptEither 之间的转换很容易。运行时表示是相同的,甚至。

我会一直选择使用 Either。它在图书馆无处不在。我很少看到 Except

ExceptExceptT 的特例,您 在图书馆中看到。如果你发现自己用 Reader SomeType (Either e a)IO (Either e a)Monad m => m (Either e a) 编写了很多函数,那么你可能要考虑 ExceptT。在那之前不要担心 - Either 更容易使用,直到它不是。

区别在于 Alternative 的实例。 "base" 包不会为 Either 导出任何内容,据我所知,因为作者不想引入对任何值的偏见,这本身是因为 Either 应该是是一般的求和类型,表示出错的可能性只是特例。然而 the "transformers" package does provide an orphan instance, which binds it to the Error class:

Error e => Alternative (Either e)

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

的实例

Except 类型确实有一个非孤立实例,它甚至不将用户绑定到任何虚构的 类,而是 Monoid

(Monad m, Monoid e) => Alternative (ExceptT e m)

还值得注意的是,对于处理验证和累积所有错误的情况,the Validation abstraction 更合适。但是有一个权衡:它不能是一个 monad,但它是一个选择性的(在 applicative 和 monad 之间)和一个替代。