Extracting a Maybe value in IO - haskell

Given the following:
> (liftM2 fromMaybe) (ioError $ userError "OOPS") (return $ Just "ok")
ghci gives me
*** Exception: user error (OOPS)
Of course, fromMaybe is working correctly:
> (liftM2 fromMaybe) (return $ "not me") (return $ Just "ok")
"ok"
But it seems that the IO operation is being carried out and then discarded:
> (liftM2 fromMaybe) (putStrLn "computing.." >> "discarded") (return $ Just "ok")
computing..
"ok"
Why is this happening? Is there any way to make the IO monad lazier?
Specifically, given value :: IO (Maybe a) what's a (clean, concise) way to say
result <- (liftM2 fromMaybe) err value
and have it unpack result or throw an IOError accordingly?

I don't know that making IO lazier is the right direction here. What you seem to want to do is first get at the Maybe, then eliminate it. This can be written several ways, here's one option:
test :: IO (Maybe a) -> IO a
test = (>>= maybe (ioError $ userError "oops") return)

If you translate from liftM2 to do-notation, it's obvious why your code fails:
do x <- ioError $ userError "OOPS"
y <- return $ Just "ok"
return $ fromMaybe x y
This will never go past the first line, as it's unconditionally throwing an exception.
Anthony's suggestion will work fine, but if you don't care about the specific exception thrown, you can also use pattern matching:
do Just result <- value
If the pattern doesn't match, this will call fail, which in the case of the IO monad throws an exception.
> Just x <- return Nothing
*** Exception: user error (Pattern match failure in do expression at <interactive>:1:0-5)

what's a (clean, concise) way to ... unpack [the] result or throw an IOError accordingly?
I recommend you avoid relying on throwing errors. Instead, handle the "error" explicitly:
maybeM :: Monad m => m b -> (a -> m b) -> m (Maybe a) -> m b
maybeM err f value = do
x <- value
case x of
Just y -> f y
Nothing -> err
-- This can be written simply as:
maybeM err f value = do
x <- value
maybe err f x
-- or even shorter! This is starting to look like Anthony's answer :)
maybeM err f value = value >>= maybe err f
The function's inputs and types should speak for themselves. You use it by giving it an action to perform for the Nothing case, or a function to perform on the value inside for the Just case. For your particular inputs this would look like:
maybeM (ioError $ userError "OOPS") return (return $ Just "ok")
So if you absolutely must, then the "concise way to unpack the result or throw an IOError" would be:
-- compare to fromJust, a function to be avoided
fromJustIO :: IO (Maybe a) -> IO a
fromJustIO = maybeM (ioError $ userError "OOPS") return
Notice how the type signature for this is practically Maybe a -> a, which is the essence of magicMonadUnwrap :: Monad m => m a -> a, which should set off some red flags. However, you can use this atrocity in a simple manner:
result <- fromJustIO value
Although again, I strongly discourage the use of exceptions here. Try handling errors in a more elegant way than simply exploding, by using maybeM and providing an IO action to execute in the event of failure.

Related

Trying to understand error-catching in Haskell

While trying to write a program in Haskell, I suddenly realized that I apparently don't understand how error throwing/catching excetions works. While my actual case is significantly more complicated, I've come up with a seemingly minimal example displaying what I don't understand:
import Control.Exception
import Control.Monad
import Data.Typeable
data IsFalse = IsFalse
deriving (Show, Typeable)
instance Exception IsFalse
isTrue :: Bool -> Bool
isTrue b = if b then b else throw IsFalse
catchesFalse :: Bool -> IO ()
catchesFalse = try . return . isTrue >=> either (\e -> fail $ displayException (e :: IsFalse)) (const $ putStrLn "uh-oh")
main :: IO ()
main = catchesFalse False
When running with runhaskell, I would expect the above code to fail and print IsFalse. However, it instead prints uh-oh. On the other hand, if I replace the definition of catchesFalse by
catchesFalse = try . return . isTrue >=> either (\e -> fail $ displayException (e :: IsFalse)) print
then the exception is caught, just as I would expect.
I'm hoping that someone can point me to any resources that could help me understand the discrepency between these two functions. My best guess is that there's something going on with lazy evaluation, but I'm not sure.
If this is indeed the case, what's the best method to force Haskell to evaluate an expression to the point where it could catch an exception? Forgive me, I understand that this particular question likely has many answers depending on what I actually care to evaluate (which, in my actual case, isn't anywhere near as simple as Bool).
What you probably want is evaluate:
catchesFalse = try . evaluate . isTrue >=> either (\e -> fail $ displayException (e :: IsFalse)) (const $ putStrLn "uh-oh")
With this definition, catchesFalse False will result in
*** Exception: user error (IsFalse)
Note that the user error here is a hint that this has actually been produced by fail.
Both your examples don't "catch" the exception. The second one triggers it by means of calling print.
Exceptions in "pure" (i.e., non-IO) computations are tricky. In fact, we have the following equalities
try (return e) >>= f
=
return (Right e) >>= f
=
f (Right e)
Let's look at the first equation, which is probably the more surprising. The function try is implemented in terms of catch, and catch wraps the given IO computation and checks whether in its execution there are any effects. However, execution does not mean evaluation, and it only concerns the "effectful" part of the computation. A return is a trivial IO computation that "succeeds" immediately. Neither catch nor try are going to act on this, regardless of what the result looks like.
The second equation simply follows from the monad laws.
If we keep this in mind, and apply equational reasoning to your examples, we get in the first case:
catchesFalse False
=
(try . return . isTrue >=> either (\ e -> fail $ displayException (e :: IsFalse)) (const $ putStrLn "uh-oh")) False
=
try (return (isTrue False)) >>= either (\ e -> fail $ displayException (e :: IsFalse)) (const $ putStrLn "uh-oh")
=
return (Right (isTrue False)) >>= either (\ e -> fail $ displayException (e :: IsFalse)) (const $ putStrLn "uh-oh")
=
either (\ e -> fail $ displayException (e :: IsFalse)) (const $ putStrLn "uh-oh") (Right (isTrue False))
=
(const $ putStrLn "uh-oh") (isTrue False)
=
putStrLn "uh-oh"
So as you can see, the exception is never even triggered.
In the second example, everything is the same until almost the end, and we get
either (\ e -> fail $ displayException (e :: IsFalse)) print (Right (isTrue False))
=
print (isTrue False)
Now, when executing this, print will force its argument, and thereby trigger the exception, and this will yield the output:
*** Exception: IsFalse
This is coming directly from throw, not from your handler; there's not user error in the output.
The use of evaluate changes this in returning an IO action that forces its argument to weak head normal form before "returning", thereby lifting a certain amount of exceptions that arise during evaluation of the argument expression into exceptions that can be caught during execution of the resulting IO action.
Note, however, that evaluate does not fully evaluate its argument, but only to weak head normal form (i.e., the outermost constructor).
All in all, a lot of care is necessary here. In general, it is advisable to avoid exceptions in "pure" code, and to use types that explicitly allow failure (such as Maybe and variants) instead.

How to do control flow in Haskell

I'll give an example of what I want to do right away.
version1 :: IO ()
version1 =
if boolCheck
then case maybeCheck of
Nothing -> putStrLn "Error: simple maybe failed"
Just v -> case eitherCheck of
Left e -> putStrLn $ "Error: " ++ show e
Right w -> monadicBoolCheck v >>= \case
False -> putStrLn "Error: monadic bool check failed"
True -> print "successfully doing the thing"
else putStrLn "simple bool check failed"
Basically I want to "do a thing" under the condition that a number of checks turns out positive.
Whenever a single check turns out negative, I want to preserve the information about the offending check and abort the mission.
In real life those checks have different types, therefore I called them
boolCheck :: Bool
maybeCheck :: Maybe a
eitherCheck :: Show a => Either a b
monadicBoolCheck :: Monad m => m Bool
Those are just examples.
Feel free to also think of monadic Maybe, EitherT or a a singleton list where I extract head and fail when it is not a singleton.
Now I am trying to improve the above implementation and the Either monad came into my mind, because it has the notion of aborting with an error message.
version2 :: IO ()
version2 = do
result <- runEitherT $ do
if boolCheck
then pure ()
else left "simple bool check failed"
v <- case maybeCheck of
Just x -> pure x
Nothing -> left "simple maybe check failed"
w <- hoistEither . mapLeft show $ eitherCheck
monadicBoolCheck v >>= \case
True -> pure ()
False -> left "monadic bool check failed"
case result of
Left msg -> putStrLn $ "Error: " ++ msg
Right _ -> print "successfully doing the thing"
While I prefer version2, the improvement in readability is probably marginal.
Version2 is superior when it comes to adding further checks.
Is there an ultimately elegant way of doing this?
What I don't like:
1) I am partly abusing the Either monad and what I actually do is more like a Maybe monad with the rolls of Just and Nothing switched in the monadic bind
2) The conversion of the checks to Either requires either rather verbose use of case or a conversion function (like hoistEither).
Ways of improving readability might be:
1) define helper functions to allow code like
v <- myMaybePairToEither "This check failed" monadicMaybePairCheck
monadicMaybePairCheck :: Monad m => m (Maybe x, y)
...
myMaybePairToEither :: String -> m (Maybe x, y) -> EitherT m e z
myMaybePairToEither _ (Just x, y) = pure $ f x y
myMaybePairToEither msg (Nothing, _) = left msg
2) consistently use explicit cases, not even use hoistEither
3) defining my own monad to stop the Either abuse ... I could provide all the conversion functions along with it (if no-one has already done something like that)
4) use maybe and either where possible
5) ... ?
Use maybe, either, and the mtl package. By the by, eitherCheck :: Show a => Either a b's Show a constraint is probably not what you want: it lets callers choose whatever type they want as long as the type implements Show a. You were probably intending having a be a type such that callers would only be able to call show on the value. Probably!
{-# LANGUAGE FlexibleContexts #-}
newtype Error = Error String
gauntlet :: MonadError Error m => m ()
gauntlet = do
unless boolCheck (throw "simple bool check failed")
_ <- maybe (throw "simple maybe check failed") pure maybeCheck
_ <- either throw pure eitherCheck
x <- monadicBoolCheck
unless x (throw "monadic bool check failed")
return ()
where
throw = throwError . Error
version2 :: IO ()
version2 =
putStrLn (case gauntlet of
Left (Error e) ->
"Error: " ++ e
Right _ ->
"successfully doing thing")
"Define helper functions" is exactly how I would handle this. The errors library provides many already, with the possible exception of satisfying Bool functions. For those I would just use when/unless.
And of course, to the extent possible, you should promote the actions you're calling to be suitably polymorphic so that no conversion is needed.
So I'd probably start by reworking your version2 into something like
import Control.Monad.Trans
import Control.Monad.Trans.Either hiding (left, right)
import Control.Monad
import Control.Applicative
import Control.Arrow
version3 :: IO ()
version3 = eitherT onFailure onSuccess $ do
guard boolCheck <|> fail "simple bool check failed"
v <- hoistEither $ maybe (Left "simple maybe check failed") Right maybeCheck
w <- hoistEither . left show $ eitherCheck
lift (guard =<< monadicBoolCheck v) <|> fail "monadic boolcheck failed"
where
onFailure msg = putStrLn $ "Error: "++msg
onSuccess _ = print "successfully doing the thing"
Which I find more readable, but is still a bit awkward, so if I was doing a lot
of code like this, I'd introduce some helpers:
version4 :: IO ()
version4 = eitherT onFailure onSuccess $ do
failUnless "simple bool check failed" boolCheck
v <- hoistMaybe "simple maybe check failed" maybeCheck
w <- hoistEitherWith show eitherCheck
failUnless "monadic boolcheck failed" =<< lift (monadicBoolCheck v)
where
onFailure msg = putStrLn $ "Error: "++msg
onSuccess _ = print "successfully doing the thing"
failUnless :: Monad m => String -> Bool -> m ()
failUnless _ True = return ()
failUnless msg _ = fail msg
hoistMaybe :: Monad m => e -> Maybe a -> EitherT e m a
hoistMaybe err = hoistEither . maybe (Left err) Right
hoistEitherWith :: Monad m => (e -> e') -> Either e a -> EitherT e' m a
hoistEitherWith f = hoistEither . left f
In order to have the full range of possible options here, check out this gist:
https://gist.github.com/rubenmoor/c390901247e4e7bb97cf
It defines several helper functions, basically combining maybe, either and such with throwError. and results in code like this.
gauntlet :: MonadError Error m => m (a, b, c)
gauntlet = do
assertTrue boolCheck $ Error "simple bool check failed"
v <- assertJust maybeCheck $ Error "simple maybe check failed"
assertNothing maybeCheck' $ Error . show
w <- assertRight eitherCheck $ Error . show
b <- monadicBoolCheck
assertTrue b $ Error "monadic bool check failed"
x <- assertSingletonList list $ Error "list not singleton"
pure (v, w, x)
version3 :: IO ()
version3 = putStrLn $
case gauntlet of
Left (Error e) -> "Error: " ++ e
Right result -> "successfully doing thing with result"

Enforcing strictness in Haskell

While doing some TTD in Haskell, I recently developed the following function:
import Test.HUnit
import Data.Typeable
import Control.Exception
assertException :: (Show a) => TypeRep -> IO a -> Assertion
assertException errType fun = catch (fun >> assertFailure msg) handle
where
msg = show errType ++ " exception was not raised!"
handle (SomeException e) [...]
The function takes a Type representation of an expected exception and an IO action. The problem is that most of the time I don't get the exception thrown even though I should have been, because of laziness. Often failing parts of fun are actually never evaluated here.
To remedy this i tried to replace (fun >> assertFailure msg) with (seq fun $ assertFailure msg). I also tried to enable BangPatterns extension and put a bang before fun binding, but none of it helped. So how can I really force Haskell to evaluate fun strictly?
You have to distinguish between:
Evaluating the value of type IO a
Running the action represented by it, which may have side effects and returns a value of type a, and
Evaluating the result of type a (or parts of it).
These always happen in that order, but not necessarily all of it. The code
foo1 :: IO a -> IO ()
foo1 f = do
seq f (putStrLn "done")
will do only the first, while
foo2 :: IO a -> IO ()
foo2 f = do
f -- equivalent to _ <- f
putStrLn "done"
also does the second and finally
foo3 :: IO a -> IO ()
foo3 f = do
x <- f
seq x $ putStrLn "done"
also does the third (but the usual caveats of using seq on a complex data type like lists apply).
Try these arguments and observe that foo1, foo2 and foo3 treat them differently.
f1 = error "I am not a value"
f2 = fix id -- neither am I
f3 = do {putStrLn "Something is printed"; return 42}
f4 = do {putStrLn "Something is printed"; return (error "x has been evaluated")}
f5 = do {putStrLn "Something is printed"; return (Just (error "x has been deeply evaluated"))}
You probably need to force the value to its normal form, not just its weak head normal form. For example, evaluating Just (error "foo") to WHNF won't trigger the exception, it'll just evaluate Just. I'd use the combination of evaluate (which allows to properly sequence forced evaluation with IO actions) and rnf (or force if you'd need the value for something):
assertException :: (Show a) => TypeRep -> IO a -> Assertion
assertException errType fun =
catch (fun >>= evaluate . rnf >> assertFailure msg) handle
where ...
However, be careful, as assertFailure is implemented using exceptions, so wrapping into the catch block might catch it as well. So I'd suggest to evaluate the computation using try and call assertFailure outside the try block:
import Test.HUnit
import Data.Typeable
import Control.DeepSeq
import Control.Exception
assertException :: (NFData a, Show a) => TypeRep -> IO a -> Assertion
assertException errType fun =
(try (fun >>= evaluate . rnf) :: IO (Either SomeException ())) >>= check
where
check (Right _) =
assertFailure $ show errType ++ " exception was not raised!"
check (Left (SomeException ex))
| typeOf ex == errType = return () -- the expected exception
| otherwise = assertFailure
$ show ex ++ " is not " ++ show errType

How do I combine IOError exceptions with locally relevant exceptions?

I am building a Haskell application and trying to figure out how I am going to build the error handling mechanism. In the real application, I'm doing a bunch of work with Mongo. But, for this, I'm going to simplify by working with basic IO operations on a file.
So, for this test application, I want to read in a file and verify that it contains a proper fibonnacci sequence, with each value separated by a space:
1 1 2 3 5 8 13 21
Now, when reading the file, any number of things could actually be wrong, and I am going to call all of those exceptions in the Haskell usage of the word.
data FibException = FileUnreadable IOError
| FormatError String String
| InvalidValue Integer
| Unknown String
instance Error FibException where
noMsg = Unknown "No error message"
strMsg = Unknown
Writing a pure function that verifies the sequence and throws an error in the case that the sequence is invalid is easy (though I could probably do better):
verifySequence :: String -> (Integer, Integer) -> Either FibException ()
verifySequence "" (prev1, prev2) = return ()
verifySequence s (prev1, prev2) =
let readInt = reads :: ReadS Integer
res = readInt s in
case res of
[] -> throwError $ FormatError s
(val, rest):[] -> case (prev1, prev2, val) of
(0, 0, 1) -> verifySequence rest (0, 1)
(p1, p2, val') -> (if p1 + p2 /= val'
then throwError $ InvalidValue val'
else verifySequence rest (p2, val))
_ -> throwError $ InvalidValue val
After that, I want the function that reads the file and verifies the sequence:
type FibIOMonad = ErrorT FibException IO
verifyFibFile :: FilePath -> FibIOMonad ()
verifyFibFile path = do
sequenceStr <- liftIO $ readFile path
case (verifySequence sequenceStr (0, 0)) of
Right res -> return res
Left err -> throwError err
This function does exactly what I want if the file is in the invalid format (it returns Left (FormatError "something")) or if the file has a number out of sequence (Left (InvalidValue 15)). But it throws an error if the file specified does not exist.
How do I catch the IO errors that readFile may produce so that I can transform them into the FileUnreadable error?
As a side question, is this even the best way to do it? I see the advantage that the caller of verifyFibFile does not have to set up two different exception handling mechanisms and can instead catch just one exception type.
You might consider EitherT and the errors package in general. http://hackage.haskell.org/packages/archive/errors/1.3.1/doc/html/Control-Error-Util.html has a utility tryIO for catching IOError in EitherT and you could use fmapLT to map error values to your custom type.
Specifically:
type FibIOMonad = EitherT FibException IO
verifyFibFile :: FilePath -> FibIOMonad ()
verifyFibFile path = do
sequenceStr <- fmapLT FileUnreadable (tryIO $ readFile path)
hoistEither $ verifySequence sequenceStr (0, 0)
#Savanni D'Gerinel: you are on the right track. Let's extract your error-catching code from verifyFibFile to make it more generic, and modify it slightly so that it works directly in ErrorT:
catchError' :: ErrorT e IO a -> (IOError -> ErrorT e IO a) -> ErrorT e IO a
catchError' m f =
ErrorT $ catchError (runErrorT m) (fmap runErrorT f)
verifyFibFile can now be written as:
verifyFibFile' :: FilePath -> FibIOMonad ()
verifyFibFile' path = do
sequenceStr <- catchError' (liftIO $ readFile path) (throwError . FileUnReadable)
ErrorT . return $ verifySequence sequenceStr' (0, 0)
Notice what we have done in catchError'. We have stripped the ErrorT constructor from the ErrorT e IO a action, and also from the return value of the error-handling function, knowing than we can reconstruct them afterwards by wrapping the result of the control operation in ErrorT again.
Turns out that this is a common pattern, and it can be done with monad transformers other than ErrorT. It can get tricky though (how to do this with ReaderT for example?). Luckily, the monad-control packgage already provides this functionality for many common transformers.
The type signatures in monad-control can seem scary at first. Start by looking at just one function: control. It has the type:
control :: MonadBaseControl b m => (RunInBase m b -> b (StM m a)) -> m a
Let's make it more specific by making b be IO:
control :: MonadBaseControl IO m => (RunInBase m IO -> IO (StM m a)) -> m a
m is a monad stack built on top of IO. In your case, it would be ErrorT IO.
RunInBase m IO is a type alias for a magical function, that takes a value of type m a and returns a value of type IO *something*, something being some complex magic that encodes the state of the whole monad stack inside IO and lets you reconstruct the m a value afterwards, once you have "fooled" the control operation that only accepts IO values. control provides you with that function, and also handles the reconstruction for you.
Applying this to your problem, we rewrite verifyFibFile once more as:
import Control.Monad.Trans.Control (control)
import Control.Exception (catch)
verifyFibFile'' :: FilePath -> FibIOMonad ()
verifyFibFile'' path = do
sequenceStr <- control $ \run -> catch (run . liftIO $ readFile path)
(run . throwError . FileUnreadable)
ErrorT . return $ verifySequence sequenceStr' (0, 0)
Keep in mind that this only works when the proper instance of MonadBaseControl b m exists.
Here is a nice introduction to monad-control.
So, here's an answer that I have developed. It centers around getting readFile wrapped into the proper catchError statement, and then lifted.
verifyFibFile :: FilePath -> FibIOMonad ()
verifyFibFile path = do
contents <- liftIO $ catchError (readFile path >>= return . Right) (return . Left . FileUnreadable)
case contents of
Right sequenceStr' -> case (verifySequence sequenceStr' (0, 0)) of
Right res -> return res
Left err -> throwError err
Left err -> throwError err
So, verifyFibFile gets a little more nested in this solution.
readFile path has type IO String, obviously. In this context, the type for catchError will be:
catchError :: IO String -> (IOError -> IO String) -> IO String
So, my strategy was to catch the error and turn it into the left side of an Either, and turn the successful value into the right side, changing my data type to this:
catchError :: IO (Either FibException String) -> (IOError -> IO (Either FibException String)) -> IO (Either FibException String)
I do this by, in the first parameter, simply wrapping the result into Right. I figure that I won't actually execute the return . Right branch of the code unless readFile path was successful. In the other parameter to catch, I start with an IOError, wrap it in Left, and then return it back into the IO context. After that, no matter what the result is, I lift the IO value up into the FibIOMonad context.
I'm bothered by the fact that the code gets even more nested. I have Left values, and all of those Left values get thrown. I'm basically in an Either context, and I had thought that one of the benefits Either's implementation of the Monad class was that Left values would simply be passed along through the binding operations and that no further code in that context would be executed. I would love some elucidation on this, or to see how the nesting can be removed from this function.
Maybe it can't. It does seem that the caller, however, can call verifyFibFile repeatedly and execution basically stops the first time verifyFibFile returns an error. This works:
runTest = do
res <- verifyFibFile "goodfib.txt"
liftIO $ putStrLn "goodfib.txt"
--liftIO $ printResult "goodfib.txt" res
res <- verifyFibFile "invalidValue.txt"
liftIO $ putStrLn "invalidValue.txt"
res <- verifyFibFile "formatError.txt"
liftIO $ putStrLn "formatError.txt"
Main> runErrorT $ runTest
goodfib.txt
Left (InvalidValue 17)
Given the files that I have created, both invalidValue.txt and formatError.txt cause errors, but this function returns Left (InvalidValue ...) for me.
That's okay, but I still feel like I've missed something with my solution. And I have no idea whether I'll be able to translate this into something that makes MongoDB access more robust.

ErrorT catchError in practice

I have a very typical setup with a set of functions in the IO monad that can throw errors. To date I have just been dealing with errors at the end of the monad chain by pattern matching the Either result from runErrorT:
replLisp :: LispScope -> String -> IO String
replLisp s input = do
result <- runErrorT (evalLisp s input)
return $ either (id) (show) result
I would now like to add some error handling to my Hacked little scheme, but I'm having trouble making the type checker happy.
How does one use catchError? An example or two would be helpful.
This is my latest attempt:
catch :: [LispVal] -> IOThrowsError LispVal
catch [action rescue] = do
eval action >>= catchError $ eval rescue
Here is an example use of catchError to recover from a prior call to throwError:
import Control.Monad.Error
import Control.Monad.Identity
type MyMonad = ErrorT String Identity
runMyMonad = runIdentity . runErrorT
main = do
let x = runMyMonad (func 5 0)
print x
func :: Double -> Double -> MyMonad Double
func w x = do
y <- (divider x) `catchError` (\_ -> return 1)
return (w + y)
divider :: Double -> MyMonad Double
divider x = do
when (x == 0) (throwError "Can not divide by zero!")
return (10 / x)
Despite passing 0 in for division we can complete with the handlers result of 1 to obtain output of Right 6.0.
Does this help? Your question didn't really say what the issue was.
Error monads like Either and Maybe don't allow you to observe the error from within the same monad: you have to run the monad in order to observe it. Exceptions in IO are one notable exception (ahem) because IO is the end of the line... you can't go any further from there.
You have a few possibilities:
Since you're writing a mini-interpreter, it's probably a good idea to explicitly manage all the exceptions, using the ErrorT monad only for true, unrecoverable errors.
For any call that may error that you want to be able to recover from, perform a runErrorT and inspect that result, before passing along the result in the current monad.

Resources