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

时间:2018-11-07 14:31:41

标签: haskell error-handling exception-handling user-input

我有一个可以从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胜过{{1}在这种情况下? EitherExcept的功能和习语之间有什么区别?

2 个答案:

答案 0 :(得分:3)

不同的是在实例Alternative。正如我猜想的那样,“基本”包不会为Either导出任何内容,因为作者不想对任何值引入偏见,这本身就是因为Either应该是一般的总和型,不只是代表可能的错误。但是the "transformers" package does provide an orphan instance会将其绑定到the Error class

Error e => Alternative (Either e)

但是,社区从未接受过该类型类或孤立实例,因此现在不推荐使用它。哎呀,您可以将其视为Either仍然没有Alternative的实例。

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

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

答案 1 :(得分:1)

如注释中所述,很容易在EitherEither之间进行转换。运行时表示形式也相同。

我总是选择使用Except。它在图书馆中无处不在。我很少看到Except

Reader SomeType (Either e a)ExceptT的特例,您会在库中看到它们。如果您发现自己使用IO (Either e a)Monad m => m (Either e a)ExceptT编写了很多函数,那么您可能要考虑使用Either。最好不要担心,直到{{1}}都更容易使用。