Last active
October 5, 2015 18:09
-
-
Save spl/ba42e143d3c56af755b9 to your computer and use it in GitHub Desktop.
Either fail
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ ghci | |
GHCi, version 7.10.2: http://www.haskell.org/ghc/ :? for help | |
-- This is a similar to a function found in some library somewhere. | |
Prelude> let lookupM k v = maybe (fail $ show k ++ " not found in " ++ show v) return $ lookup k v | |
Prelude> :t lookupM | |
lookupM | |
:: (Eq a1, Monad m, Show a, Show a1) => a1 -> [(a1, a)] -> m a | |
-- What happens when you use Either as the monad? | |
Prelude> lookupM "a" [] :: Either String Int | |
*** Exception: "a" not found in [] | |
-- Oops! I expected: Left "\"a\" not found in []" | |
-- But maybe we should use ErrorT, as suggested by @JohnLato. | |
Prelude> :m +Control.Monad.Trans.Error | |
<interactive>:1:1: Warning: | |
Module ‘Control.Monad.Trans.Error’ is deprecated: | |
Use Control.Monad.Trans.Except instead | |
Prelude Control.Monad.Trans.Error> :t runErrorT $ lookupM "a" [] | |
runErrorT $ lookupM "a" [] | |
:: (Monad m, Show a, Error e) => m (Either e a) | |
Prelude Control.Monad.Trans.Error> runErrorT $ lookupM "a" [] :: IO (Either String ()) | |
Left "\"a\" not found in []" | |
-- That works, but ErrorT is deprecated in favor of ExceptT. | |
-- Let's try ExceptT. | |
Prelude Control.Monad.Trans.Error> :m -Control.Monad.Trans.Error | |
Prelude> :m +Control.Monad.Trans.Except | |
Prelude Control.Monad.Trans.Except> :t runExceptT $ lookupM "a" [] | |
runExceptT $ lookupM "a" [] :: (Monad m, Show a) => m (Either e a) | |
Prelude Control.Monad.Trans.Except> runExceptT $ lookupM "a" [] :: IO (Either String ()) | |
*** Exception: user error ("a" not found in []) | |
-- Hmm, that's not what we want. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
ErrorT
can do that because of theError e
constraint on theMonad (ErrorT e m)
instance. That has its own problems though, since not everything is an instance ofError
. SoExceptT
andEither
have a more general instance forMonad
, without the constraint. That means they can't do anything infail
, sincee
is polymorphic, and not known to beString
.I basically treat
fail
like it's deprecated. I don't use it, since too many instances can't implement it so there's the risk of bottoms everywhere. I'm also suspicious of any function with just aMonad
constraint, especially if it's a parsing or lookup like thing. I can't wait for something like the MonadFail proposal to go through.