问题
I have a class that can be created from several arguments in Haskell which requires some complex validation of those arguments. Currently I have something like
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)
Setting aside whether there is a better way to do this by using more specific types than String
as arguments to makeAThingExcept
, is there a reason to prefer Except
over Either
in a case like this? What are the differences here between the capabilities and idiom of Except
vs Either
?
回答1:
As noted in the comments, it's easy to convert between Except
& Either
. The runtime representation is the same, even.
I would always choose to use Either
. It's ubiquitous in libraries. I very rarely see Except
.
Except
is a special case of ExceptT, which you will see in libraries. If you find yourself writing a lot of functions with Reader SomeType (Either e a)
or IO (Either e a)
or Monad m => m (Either e a)
, then you might want to consider ExceptT
. It's fine not to worry about it until then - Either
is easier to use until it isn't.
回答2:
The difference is in the instance of Alternative
. The "base" package does not export any for Either
, as I guess because the authors didn't want to introduce a bias towards any of the values, which on itself is because Either
is supposed to be a general sum-type, not just for representing possible errors. However the "transformers" package does provide an orphan instance, which binds it to the Error class:
Error e => Alternative (Either e)
However the community never accepted neither that typeclass or the orphan instance, which is why it is now deprecated. IOW you can look at this as if Either
still has no instance of Alternative
.
The Except
type does have a non-orphan instance, which doesn't even bind the user to any made-up classes, but Monoid
instead:
(Functor m, Monad m, Monoid e) => Alternative (ExceptT e m)
来源:https://stackoverflow.com/questions/53191510/what-are-the-difference-in-usage-between-either-and-except-in-haskell