How to throw an exception and exit the program in Haskell? - exception

I have a question: how do I throw an exception and exit the program? I have writen down a simple example:
-- main.hs
import Test
main = do
Test.foo ""
putStrLn "make some other things"
Here is the module:
moldule Test where
foo :: String -> IO ()
foo x = do
if null x
then THROW EXCEPTION AND EXIT MAIN else putStrLn "okay"
I want to start this and throw a exception and exit the program, but how?

Well, you could try
foo :: String -> IO ()
foo x = do
if null x
then error "Oops!" else putStrLn "okay"
Or, if you intend to catch the error eventually, then
import Control.Exception
data MyException = ThisException | ThatException
deriving (Show, Typeable)
instance Exception MyException
...
foo :: String -> IO ()
foo x = do
if null x
then throw ThisException else putStrLn "okay"
There are often more haskelly mechanisms that you could use, such as returning values packed in Maybe type or some other structure that describes the failure. Exceptions seem to fit better in cases where returning complicated types would complicate otherwise re-usable interfaces too much.

Related

Error vs ErrorEvent - Use catchException in Purescript to handle an Exception

I'm trying to replicate an example from the Read PureScript by Example book.
I am getting this error:
Could not match type
Error
with type
ErrorEvent
Here is code I have been using to try and make a POC of that example.
import Prelude
import Control.Monad.Eff
import Control.Monad.Eff.Console (CONSOLE, log)
import Control.Monad.Eff.Exception (EXCEPTION, Error, throwException, catchException, error)
import DOM.HTML.Event.ErrorEvent (message)
grumpyGills :: forall eff. Boolean -> Eff (err :: EXCEPTION | eff) String
grumpyGills ateVegetables = if (ateVegetables)
then pure("Good Boy")
else throwException (error "Eat your vegetables")
main = do
test <- catchException handle $ grumpyGills true
log test
where
handle e = do
log (message e)
pure("oh well")
Problem is essentially the same as this example, except I get the same compile error when trying to use the code posted: How do I return a value from a PureScript function with an EXCEPTION effect?. I don't see what I'm doing differently.
I can see the type of ErrorEvent and Error are different. I can also see that catchException is expecting an Error hence the compilation failure. I just don't see what I'm doing wrong, and how to fix it.
using:
"purescript-exceptions": "^2.0.0"
"purescript-dom": "^3.6.0",
I found out I was using the wrong message.
I should have been using the message imported from here. (Control.Monad.Eff.Exception)
NOT this message (DOM.HTML.Event.ErrorEvent)
Notice the type signatures are different.. derp.
The fixed imports look like this:
import Prelude
import Control.Monad.Eff
import Control.Monad.Eff.Console (CONSOLE, log)
import Control.Monad.Eff.Exception (EXCEPTION, Error, throwException, catchException, error, message)
-- import DOM.HTML.Event.ErrorEvent (message) -- Don't import message from here!
I had a second issue:
Could not match type
( err :: EXCEPTION
)
with type
( console :: CONSOLE
, err :: EXCEPTION
| t0
)
That I fixed by adding extensible effects to my grumpyGills type definition.
grumpyGills :: forall eff. Boolean -> Eff (err :: EXCEPTION | eff) String
This would also work:
grumpyGills :: Boolean -> Eff (err :: EXCEPTION, console :: CONSOLE) String

Defining and Catching Exceptions

I'm still getting the hang of haskell, and am trying to build my first "real" coding project, i.e. one where I'm going to including testing, write up documentation, etc. I'm sufficiently new to haskell where I know I don't have a lot of the knowledge of the language necessary so that everything I want to do is immediately within reach, but that's kind of the idea, so that the act of finishing will require that I touch most of the major pieces of the language.
Anyway, so the current issue I'm having is regarding throwing and catching exceptions in the language, something that I understand can be done with quite varied approaches. I have a function here, toLower:
toLower :: String -> String
toLower plaintext =
if (catch (nonAlpha plaintext) handlerNonAlpha)
then map charToLower plaintext
else exitFailure
Which will take a string, throw an exception and exit if the string includes any non-alpha characters (so if not A-Z or a-z), or if not convert the string to lowercase. So what I have for the nonAlpha function is:
--- detect non-alpha character - throw error if existant
data NonNumericException = NonNumException
instance Exception NonNumericException
handlerNonAlpha :: NonNumericException -> IO()
handlerNonAlpha ex =
putStrLn "Caught Exception: " ++ (show ex) ++ " - A non-alpha character was included in the plaintext."
nonAlpha :: String -> Bool
nonAlpha str =
let nonalphas = [x | x <- str, (ord x) < 65 || (90 < (ord x) && (ord x) < 97) || 123 < (ord x)]
in if (length nonalphas) == 0
then True
else throw NonNumException
As I said I'm pretty new to haskell, so I'm a little vague on how this data/instance structure works, but as I understand it I'm defining an parent NonNumericException, of which NonNumException is a child (and I could have more), and in the instance line defining them to be Exceptions. The catch structure, if it detects an exception (for instance, when one is thrown at the end of nonAlpha if there is a non-alpha character), then calls the handler.
So here are the compile errors that I get:
utilities.hs:61:3:
Couldn't match expected type `[Char]' with actual type `IO ()'
In the return type of a call of `putStrLn'
In the first argument of `(++)', namely
`putStrLn "Caught Exception: "'
In the expression:
putStrLn "Caught Exception: "
++
(show ex)
++ " - A non-alpha character was included in the plaintext."
utilities.hs:61:3:
Couldn't match expected type `IO ()' with actual type `[Char]'
In the expression:
putStrLn "Caught Exception: "
++
(show ex)
++ " - A non-alpha character was included in the plaintext."
In an equation for `handlerNonAlpha':
handlerNonAlpha ex
= putStrLn "Caught Exception: "
++
(show ex)
++ " - A non-alpha character was included in the plaintext."
utilities.hs:73:7:
Couldn't match expected type `Bool' with actual type `IO ()'
In the return type of a call of `catch'
In the expression: (catch (nonAlpha plaintext) handlerNonAlpha)
In the expression:
if (catch (nonAlpha plaintext) handlerNonAlpha) then
map charToLower plaintext
else
exitFailure
utilities.hs:73:14:
Couldn't match expected type `IO ()' with actual type `Bool'
In the return type of a call of `nonAlpha'
In the first argument of `catch', namely `(nonAlpha plaintext)'
In the expression: (catch (nonAlpha plaintext) handlerNonAlpha)
utilities.hs:75:8:
Couldn't match type `IO a0' with `[Char]'
Expected type: String
Actual type: IO a0
In the expression: exitFailure
In the expression:
if (catch (nonAlpha plaintext) handlerNonAlpha) then
map charToLower plaintext
else
exitFailure
In an equation for `toLower':
toLower plaintext
= if (catch (nonAlpha plaintext) handlerNonAlpha) then
map charToLower plaintext
else
exitFailure
So I guess my two question are, a) what's going wrong with the types for the handler (the line 61 errors), and b) how do I properly set the types for the functions that may throw an exception or exit with failure, but otherwise will return a bool or a string?
EDIT: I guess I should note. I do see the similarities between this question and a number of others that have been asked. Part of what I'm looking for that I don't see is a description of what the structures here are actually doing, and what is best practice and why.
What is best practice in Haskell is to leverage the awesome power of its type system to avoid needing to throw/catch exceptions for pure functions. There are cases where throwing an exception can actually make sense, but for something like your toLower function you can just choose to have a different return type. For example:
-- We can factor out our check for a non-alpha character
isNonAlpha :: Char -> Bool
isNonAlpha c = c' < 65 || (90 < c' && c' < 97) || 123 < c'
where c' = ord c
-- Why throw an exception? Just return False
hasNonAlpha :: String -> Bool
hasNonAlpha str = any isNonAlpha str
-- Renamed to not conflict with Data.Char.toLower
myToLower :: String -> Maybe String
myToLower plaintext =
if hasNonAlpha plaintext
then Nothing
else Just $ map toLower plaintext
Not only is this cleaner code, but now we don't have to worry about error handling at all, and someone else using your code won't get a nasty surprise. Instead, the notion of failure is encoded at the type level. To use this as an "error handling" mechanism, just work in the Maybe monad:
doSomething :: String -> String -> Maybe String
doSomething s1 s2 = do
s1Lower <- myToLower s1
s2Lower <- myToLower s2
return $ s1Lower ++ s2Lower
If either myToLower s1 or myToLower s2 returns Nothing, then doSomething will return Nothing. There is no ambiguity, no chance for an unhandled exception, and no crashing at runtime. Haskell exceptions themselves, those thrown by the function throw, must be caught by catch, which has to execute in the IO monad. Without the IO monad, you can't catch exceptions. In pure functions, you can always represent the concept of failure with another data type without having to resort to throw, so there is no need to over-complicate code with it.
Alternative, you could have even written myToLower monadically as
import Control.Monad
-- Other code
myToLower :: String -> Maybe String
myToLower plaintext = do
guard $ not $ hasNonAlpha plaintext
return $ map toLower plaintext
The guard from Control.Monad acts as a sort of filter for MonadPlus instances. Since Maybe is an instance of MonadPlus (as are lists), this gives us very simple code.
Or, if you want to pass around an error message:
type MyError = String
myToLower :: String -> Either MyError String
myToLower plaintext = if hasNonAlpha plaintext
then Left $ "The string " ++ plaintext ++ " has non-alpha character(s)"
else Right $ map toLower plaintext
Then you can change the type of doSomething to match:
doSomething :: String -> String -> Either MyError String
doSomething s1 s2 = do
s1Lower <- myToLower s1
s2Lower <- myToLower s2
return $ s1Lower ++ s2Lower
If you notice, the monadic syntax lets us change the type signature of our function without even having to change the code! Play around with this implementation to get a feel for how it works.
Learning about exceptions is useful, and they are great for handling exceptional circumstances.
The best place to read about exceptions is Simon Marlow's paper, An Extensible Dynamically-Typed Heirarchy of Exceptions. His book, Parallel Concurrent Programming in Haskell is another good resource on their use.
The following are a few comments on your question.
error on line 61
handlerNonAlpha :: NonNumericException -> IO()
handlerNonAlpha ex =
putStrLn "Caught Exception: " ++ (show ex) ++ ...
Function arguments are consumed eagerly in haskell. You'll have to modify this line as follows to perform string concatenation before calling putStrLn:
putStrLn $ "Caught Exception: " ++ (show ex) ++ ...
comment on nonAlpha
Exceptions can only be caught from an IO computation, and it's best to avoid throwing them from pure functions. Besides this, the problem with nonAlpha is that it claims to return a Bool, but actually returns either True or throws an exception. Why not just return False?
nonAlpha :: String -> Bool
nonAlpha str =
let nonalphas = [x | x <- str, (ord x) < 65 || (90 < (ord x) && (ord x) < 97) || 123 < (ord x)]
in if (length nonalphas) == 0
then True
else False
Pull your exception throwing code out of nonAlpha like so. The name of this function and its lack of return value indicate that it might throw an exception:
trapInvalid :: String -> IO ()
trapInvalid str = unless (nonAlpha str) $ throw NonNumException

Catch IO exceptions within an instance of MonadResource

Short version
Same question as in here, but within a generic MonadResource instance rather than an explicit ResourceT m.
Long version
How would you define a catch function such that:
import Control.Exception (Exception, IOException)
import Control.Monad.Trans.Resource (MonadResource, runResourceT)
catch :: (MonadResource m, Exception e) -> m () -> (e -> m ()) -> m ()
catch = undefined
-- 'a' and 'b' are functions from an external library,
-- so I can't actually change their implementation
a, b :: MonadResource m => m ()
a = -- Something that might throw IO exceptions
b = -- Something that might throw IO exceptions
main :: IO ()
main = runResourceT $ do
a `catch` \(e :: IOException) -> -- Exception handling
b `catch` \(e :: IOException) -> -- Exception handling
The problems I run into are:
In Control.Exception, catch only works on bare IOs ;
In Control.Exception.Lifted, catch requires an instance of MonadBaseControl, which MonadResource is unfortunately not (and I wonder why) ;
MonadResource implies MonadThrow which defines a monadThrow function without its 'catch' equivalent (and I wonder why) ;
It looks like the only way to handle IO exceptions is to exit the ResourceT layer, and this bothers me: I'd like to be able to handle exceptions locally without travelling through the monad transformers stack.
For information, in my real code, a and b are actually the http function from Network.HTTP.Conduit.
Thank you for your insights.
Minimal code with the problem
Compilable with ghc --make example.hs with http-conduit library installed:
{-# LANGUAGE FlexibleContexts, ScopedTypeVariables #-}
import Control.Exception.Lifted (IOException, catch)
import Control.Monad.Base (liftBase)
import Control.Monad.Error (MonadError(..), runErrorT)
import Control.Monad.Trans.Control (MonadBaseControl)
import Control.Monad.Trans.Resource (MonadResource, runResourceT)
import Data.Conduit
import Data.Conduit.List (consume)
import Data.Conduit.Text (decode, utf8)
import Data.Text (Text)
import Network.HTTP.Client
import Network.HTTP.Conduit (http)
main :: IO ()
main = do
result <- runErrorT $ runResourceT f
putStrLn $ "OK: " ++ show result
f :: (MonadBaseControl IO m, MonadResource m, MonadError String m) => m [Text]
f = do
req <- liftBase $ parseUrl "http://uri-that-does-not-exist.abc"
manager <- liftBase $ newManager defaultManagerSettings
response <- (http req manager `catch` \(e :: IOException) -> throwError $ show e)
response $$+- decode utf8 =$ consume
When executed, this program ends in error with the following output:
InternalIOException getAddrInfo: does not exist (Name or service not known)
http does not throw IOException, it throws HttpException and InternalIOException is one of the latter's constructors.
You should either catch HttpException or SomeException in case you want to catch all exceptions.
The type you need,
a, b :: MonadResource m, MonadBaseControl IO m => m ()
Is a special case of the type you currently have
a, b :: MonadResource m => m ()
as the only difference is the extra class constraint. You are free to make the type signatures in your code less general than they would be by default; therefore, changing the signatures of a and b should be enough.
If I understand your problem correctly, there is no problem with using lifted-base. Although the type of a and b only use the constraint MonadResource m, it doesn't mean you can't use them on a monad that has other additional properties. For example, if you perform your computation inside ResourceT, it satisfies the constraint for a and b, and you can also use anything from Control.Exception.Lifted:
-- ...
import Control.Exception.Lifted
-- 'a' and 'b' are functions from an external library,
-- so I can't actually change their implementation
a, b :: MonadResource m => m ()
a = undefined -- Something that might throw IO exceptions
b = undefined -- Something that might throw IO exceptions
main :: IO ()
main = runResourceT $ do
a `catch` \(e :: IOException) -> undefined -- Exception handling
b `catch` \(e :: IOException) -> undefined -- Exception handling
If you alter the type signature of catch to include MonadCatch from the exceptions package, then it would be trivial:
import Control.Monad.Trans.Resource (MonadResource, runResourceT)
import Control.Monad.Catch (catch)
a, b :: MonadResource m => m ()
a = …
b = …
main :: IO ()
main = runResourceT $ do
a `catch` \e -> …
b `catch` \e -> …
Note that this does not require any changes for a nor b.
Also, both duplode and Petr Pudlák have pointed out that you are free to make the monad for catch to be as specific as you like, because doing so does not require any cooperation from a or b. So any of these solutions will work.

Rethrowing SomeException

The function forkFinally requires you to write a handler against SomeException. What I need is a way to rethrow the unhandled exceptions. Here's a sample code, which fails to compile because on the last line the e is ambiguous:
finallyHandler :: Either SomeException () -> IO ()
finallyHandler z = case z of
Right () -> cleanUp
Left someE | Just ThreadKilled <- fromException someE -> cleanUp
| Just e <- fromException someE -> cleanUp >> throwIO e
Of course the first thing coming to mind is to simply throw the someE instead, i.e.:
...
| otherwise -> cleanUp >> throwIO someE
And indeed it will compile, but then it will result in wrapping of all of incoming exceptions in SomeException when they pass this handler. This just can't be right. And what if I have multiple such handlers down the stack - I'll get a trash like SomeException $ SomeException $ RealException.
Am I missing something? What's the proper way of handling this situation?
Are you seeing unexpected behavior? If you haven't actually triggered something undersirable then I think you are worrying over nothing. A quick test indicates that the "right thing" is already being done. That is, if you catch then throw a SomeException you can still catch the original exception. Here's an example using ErrorCall as the underlying exception:
> catch (catch (throw (SomeException (ErrorCall "hi")))
(\(e::SomeException) -> throw e))
(\(ErrorCall e) -> putStrLn e)
hi
This is because the definition of throw uses toException and toException is identity for SomeException:
instance Exception SomeException where
toException se = se
fromException = Just

How do I correctly use Control.Exception.catch in Haskell?

Can someone please explain the difference between the behavior in ghci of the following to lines:
catch (return $ head []) $ \(e :: SomeException) -> return "good message"
returns
"*** Exception: Prelude.head: empty list
but
catch (print $ head []) $ \(e :: SomeException) -> print "good message"
returns
"good message"
Why isn't the first case catching the exception? Why are they different? And why does the first case put a double quote before the exception message?
Thanks.
Let's examine what happens in the first case:
catch (return $ head []) $ \(e :: SomeException) -> return "good message"
You create thunk head [] which is returned as an IO action. This thunk doesn't throw any exception, because it isn't evaluated, so the whole call catch (return $ head []) $ ... (which is of type IO String) produces the String thunk without an exception. The exception occurs only when ghci tries to print the result afterwards. If you tried
catch (return $ head []) $ \(e :: SomeException) -> return "good message"
>> return ()
instead, no exception would have been printed.
This is also the reason why you get _"* Exception: Prelude.head: empty list_. GHCi starts to print the string, which starts with ". Then it tries to evaluate the string, which results in an exception, and this is printed out.
Try replacing return with evaluate (which forces its argument to WHNF) as
catch (evaluate $ head []) $ \(e :: SomeException) -> return "good message"
then you'll force the thunk to evaluate inside catch which will throw the exception and let the handler intercept it.
In the other case
catch (print $ head []) $ \(e :: SomeException) -> print "good message"
the exception occurs inside the catch part when print tries to examine head [] and so it is caught by the handler.
Update: As you suggest, a good thing is to force the value, preferably to its full normal form. This way, you ensure that there are no "surprises" waiting for you in lazy thunks. This is a good thing anyway, for example you can get hard-to-find problems if your thread returns an unevaluated thunk and it is actually evaluated in another, unsuspecting thread.
Module Control.Exception already has evaluate, which forces a thunk into its WHNF. We can easily augment it to force it to its full NF:
import Control.DeepSeq
import Control.Seq
import Control.Exception
import Control.Monad
toNF :: (NFData a) => a -> IO a
toNF = evaluate . withStrategy rdeepseq
Using this, we can create a strict variant of catch that forces a given action to its NF:
strictCatch :: (NFData a, Exception e) => IO a -> (e -> IO a) -> IO a
strictCatch = catch . (toNF =<<)
This way, we are sure that the returned value is fully evaluated, so we won't get any exceptions when examining it. You can verify that if you use strictCatch instead of catch in your first example, it works as expected.
return $ head []
wraps head [] in an IO action (because catch has an IO type, otherwise it would be any monad) and returns it. There is nothing caught because there is no error. head [] itself is not evaluated at that point, thanks to lazyness, but only returned.
So, return only adds a layer of wrapping, and the result of your whole catch expression is head [], quite valid, unevaluated. Only when GHCi or your program actually try to use that value at some later point, it will be evaluated and the empty list error is thrown - at a different point, however.
print $ head []
on the other hand immediately evaluates head [], yielding an error which is subsequently caught.
You can also see the difference in GHCi:
Prelude> :t head []
head [] :: a
Prelude> :t return $ head []
return $ head [] :: Monad m => m a
Prelude> :t print $ head []
print $ head [] :: IO ()
Prelude> return $ head [] -- no error here!
Prelude> print $ head []
*** Exception: Prelude.head: empty list
To avoid that, you can perhaps just force the value:
Prelude> let x = head [] in x `seq` return x
*** Exception: Prelude.head: empty list
GHCi works in the IO monad and return for IO doesn't force its argument. So return $ head [] doesn't throw any exception, and an exception that isn't thrown can't be caught. Printing the result afterwards throws an exception, but this exception isn't in the scope of catch anymore.
The type IO a has two parts:
The structure, the part that goes out and performs side-effects. This is represented by IO.
The result, the pure value held inside. This is represented by a.
The catch function only catches exceptions when they break through the IO structure.
In the first example, you call print on the value. Since printing a value requires performing I/O with it, any exceptions raised within the value end up in the structure itself. So catch intercepts the exception and all is well.
On the other hand, return does not inspect its argument. In fact, you are guaranteed by the monad laws that calling return does not affect the structure at all. So your value simply passes right through.
So if your code isn't affected by the exception, then where is the error message coming from? The answer is, surprisingly, outside your code. GHCi implicitly tries to print every expression that is passed to it. But by then, we are already outside the scope of the catch, hence the error message you see.