Haskell unit test for ErrorCall in HUnit - haskell

I've got a function:
unify :: [Constraint] -> [Substitution]
and in certain cases it throws exceptions with the error function:
error "Circular constraint"
I'm using Test.HUnit for unit testing and I'd like to make a test case that asserts these errors are thrown on certain inputs. I found this, which provides a way of testing for exceptions that are instances of Eq, but error seems to give an ErrorCall exception, which is not an instance of Eq, so I get the error:
No instance for (Eq ErrorCall)
arising from a use of `assertException'
How can I write a TestCase that asserts that error was called and (preferably) checks the message?

Ideally I'd refactor your function into
unify' :: [Constraint] -> Maybe [Substitution]
unify' = -- your original function, but return Nothing instead of calling error,
-- and return Just x when your original function would return x
unify = fromMaybe (error "Circular constraint") . unify'
I would then test unify' instead of testing unify.
If there was more than one possible error message, I would refactor it like this instead:
unify' :: [Constraint] -> Either String [Substitution]
-- and return Left foo instead of calling error foo
unify = either error id . unify'
(Incidentally, if this is for a library other programmers will be using, some of them would prefer to call unify' instead of the partial function unify.)
If you can't refactor your code, I'd modify the code you link to, replacing assertException with:
assertErrorCall :: String -> IO a -> IO ()
assertErrorCall desiredErrorMessage action
= handleJust isWanted (const $ return ()) $ do
action
assertFailure $ "Expected exception: " ++ desiredErrorMessage
where isWanted (ErrorCall actualErrorMessage)
= guard $ actualErrorMessage == desiredErrorMessage

Related

How do I create a Haskell function like error (i.e. String -> a)

In Haskell, the error function has signature String -> a. It can return any type because it never actually returns. (It prints its argument and terminates the program.)
I've written a function in C that does something similar. It logs the string that is passed and terminates the process. Is there a way I can write a Haskell wrapper to have the same signature as error?
The C function has the form void RaiseError(char* msg) { ... }
So far, I have
foreign import capi safe "file.h RaiseError"
c_RaiseError :: CString -> IO ()
raiseError :: String -> a
raiseError msg = unsafePerformIO $ do
withCString msg c_RaiseError -- Does not return
return (error "") -- Never gets called
There must be a more elegant way to do this.
You can implement a function of type String -> a in pure Haskell, but it won't have the same behavior as error:
error1 :: String -> a
error1 = error1
Calling error1 will loop forever rather than printing the message and exiting.
The function Control.Exception.throw is similar to error in that it throws an exception without needing IO. You could use it to implement your own version of error:
import Control.Exception (ErrorCall(..), throw)
error2 :: String -> a
error2 msg = throw (ErrorCall msg)
Calling error2 will be almost the same as calling error, except it won't have a call stack. (Call stacks are a relatively recent addition to error; see errorWithoutStackTrace.)
Ultimately you can't implement something like error in pure Haskell without relying on something like throw. error itself is implemented in terms of raise#, which is a primop. You can use the FFI, but you'll still have to rely on other primops like unsafePerformIO or unsafeCoerce.
This is the most elegant thing I could come up with:
import Foreign.C.String (CString, withCString)
import System.IO.Unsafe (unsafePerformIO)
import Unsafe.Coerce (unsafeCoerce)
foreign import ccall "file.h RaiseError"
c_RaiseError :: CString -> IO ()
error3 :: String -> a
error3 = unsafeCoerce
. unsafePerformIO
. flip withCString c_RaiseError

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.

Ocaml's `try ... with` in Haskell

My question: is there any "try with" equivalent in Haskell? Something like this :
try
{
head l
}
with
Failure _ -> []
If the operation in try failed we pattern match the error and do appropriate job in with section?
You should really be avoiding such errors via total functions. Then, if a function can return an error, have its return type be an Either e a where e is the type of the exception and a is the otherwise successful type. If you don't need to pass any information about the exception, you can just return Maybe a.
That said, Control.Exception has some facilities for catching errors via try or catch, at the cost of only being able to do such handling in the IO monad. At GHCi you can see this:
ghci> import Control.Exception
ghci> catch (head []) (\msg -> putStrLn $ "caught: " ++ show (msg :: SomeException))
caught: Prelude.head: empty list
You can use functions and total functions to achieve the same thing most of the time. For your example:
fromMaybe [] (listToMaybe l)
In this simple case, you could just use foldr:
foldr const [] l
Or even use pattern matching directly:
case l of
[] -> []
x : _ -> x
More generally, using Maybe or Either, as others have suggested, can make for more modular code. You may want to check out the MaybeT and ExceptT types, and the MonadError class, to integrate failure into monadic computations.

How to completely abort a Haskell runtime?

I have a function
import System.Exit
exit_and_report_type_mismatch :: String -> IO ExitCode
exit_and_report_type_mismatch error_message = do
putStrLn error_message
exitFailure
and a section of another like so
interpret_expr :: Vars -> Expr -> Val
interpret_expr vars (Plus (ConsE _ _) (NumE _)) = exit_and_report_type_mismatch "Type Error: Can only concatenate list (not int) to list"
Haskell complains to me that it is expecting type Val (another data type I have defined) but it actually receives type IO Exitcode. Fair enough - exit_and_report_mismatch is returning IO ExitCode which is not a Val.
How do I completely abort the Haskell program from within "exit_and_report_type_mismatch"? I have read a bit about Haskell exceptions but the explanations either do not make sense or mention having to call ExitWith from the main function, which is not an option.
This is what error is for. From the documentation:
error :: [Char] -> a
error stops execution and displays an error message.
For instance:
zsh% runhaskell <<<'main = putStrLn (error "Message") >> print "Not reached."'
runghcXXXX7729.hs: Message
The effect of putStrLn is ignored, and the program terminates as soon as the value produced by error is demanded (lazy evaluation means that just putting error somewhere doesn't immediately cause an error; as you might or might not expect, let x = error "Message" in putStrLn "Printed" causes no errors). It is possible to catch these exceptions with the functions from Control.Exception.Base, such as catch, but I've never done this nor have I seen this done.
Also, as a final note, consider avoiding the use of error. Partial functions (functions that aren't defined over their entire input domain) are best avoided when possible, as it's much easier to reason about your code with the stronger guarantees total functions provide. It's nice when, as for total functions, f :: A -> B really means "the function f returns something of type B"; for partial functions, f :: A -> B means only "if the function f returns, then what it returns is of type B". In your case, this might mean having a type like interpretExpr :: Vars -> Expr -> Either RuntimeError Val, or something suitably isomorphic (in the simplest case, perhaps data Result = Error String | Value Val, and interpretExpr :: Vars -> Expr -> Result).
This will do it:
import System.IO.Unsafe
exit_and_report_type_mismatch :: String -> a
exit_and_report_type_mismatch error_message = unsafePerformIO $ do
putStrLn error_message
exitFailure
The function error might work the same though.

Ambiguous type variable error msg

I don't think it is a bug, but I am a bit puzzled as to why that doesn't work. A bonus question is why does it mention variable e? There is no variable e.
Prelude> :m +Control.Exception
Prelude Control.Exception> handle (\_-> return "err") undefined
<interactive>:1:0:
Ambiguous type variable `e' in the constraint:
`Exception e'
arising from a use of `handle' at <interactive>:1:0-35
Probable fix: add a type signature that fixes these type variable(s)
Prelude Control.Exception>
Apparently it works fine in ghci 6.8, I am using 6.10.1.
Edit: I have minimized the code. I expect that to have the same result in both 6.8 and 6.10
class C a
foo :: C a => (a -> Int)-> Int
foo _ = 1
arg :: C a => a -> Int
arg _ = 2
bar :: Int
bar = foo arg
trying to compile it:
[1 of 1] Compiling Main ( /tmp/foo.hs, interpreted )
/tmp/foo.hs:12:10:
Ambiguous type variable `a' in the constraint:
`C a' arising from a use of `arg' at /tmp/foo.hs:12:10-12
Probable fix: add a type signature that fixes these type variable(s)
Failed, modules loaded: none.
Prelude Control.Exception>
The type of Control.Exception.handle is:
handle :: Exception e => (e -> IO a) -> IO a -> IO a
The problem you are seeing is that the lambda expression (\_ -> return "err") is not of type e -> IO a where e is an instance of Exception. Clear as mud? Good. Now I'll provide a solution which should actually be useful :)
It just so happens in your case that e should be Control.Exception.ErrorCall since undefined uses error which throws ErrorCall (an instance of Exception).
To handle uses of undefined you can define something like handleError:
handleError :: (ErrorCall -> IO a) -> IO a -> IO a
handleError = handle
It's essentially an alias Control.Exception.handle with e fixed as ErrorCall which is what error throws.
It looks like this when run in GHCi 7.4.1:
ghci> handleError (\_ -> return "err") undefined
"err"
To handle all exceptions a handleAll function can be written as follows:
handleAll :: (SomeException -> IO a) -> IO a -> IO a
handleAll = handle
Catching all exceptions has consequences described well in this excerpt of the Control.Exception documentation:
Catching all exceptions
It is possible to catch all exceptions, by using the type SomeException:
catch f (\e -> ... (e :: SomeException) ...)
HOWEVER, this is normally not what you want to do!
For example, suppose you want to read a file, but if it doesn't exist then continue as if it contained "". You might be tempted to just catch all exceptions and return "" in the handler. However, this has all sorts of undesirable consequences. For example, if the user presses control-C at just the right moment then the UserInterrupt exception will be caught, and the program will continue running under the belief that the file contains "". Similarly, if another thread tries to kill the thread reading the file then the ThreadKilled exception will be ignored.
Instead, you should only catch exactly the exceptions that you really want. In this case, this would likely be more specific than even "any IO exception"; a permissions error would likely also want to be handled differently. Instead, you would probably want something like:
e <- tryJust (guard . isDoesNotExistError) (readFile f)
let str = either (const "") id e
There are occassions when you really do need to catch any sort of exception. However, in most cases this is just so you can do some cleaning up; you aren't actually interested in the exception itself. For example, if you open a file then you want to close it again, whether processing the file executes normally or throws an exception. However, in these cases you can use functions like bracket, finally and onException, which never actually pass you the exception, but just call the cleanup functions at the appropriate points.
But sometimes you really do need to catch any exception, and actually see what the exception is. One example is at the very top-level of a program, you may wish to catch any exception, print it to a logfile or the screen, and then exit gracefully. For these cases, you can use catch (or one of the other exception-catching functions) with the SomeException type.
Source: http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception.html#g:4
This problem shows up only in GHC 6.10; it can't be duplicated in GHC 6.8 because the type of handle is different:
: nr#homedog 620 ; ghci
GHCi, version 6.8.2: http://www.haskell.org/ghc/ :? for help
Loading package base ... linking ... done.
Prelude> :m +Control.Exception
Prelude Control.Exception> handle (\_ -> return "err") undefined
"err"
Prelude Control.Exception>
OK maybe I can get this right at last. I think the problem is not the monomorphism restriction, but rather you've hit an instance of the Read/Show problem: you're offering to handle some type of exception, in the new version of `handle, there is more than one type of exception, and the type of that exception does not appear in your result. So the compiler has no way of knowing which type of exception you're trying to handle. One way to work this is to pick one. Here's some code that works:
Prelude Control.Exception> let alwaysError :: SomeException -> IO String; alwaysError = \_ -> return "err"
Prelude Control.Exception> handle alwaysError undefined
"err"
Incidentally, the example use of handle in the GHC library documentation does not compile under 6.10. I have filed a bug report.
A workaround is to use Control.OldException in ghc 6.10.* instead of Control.Exception.
Try giving your handler the type SomeException -> IO x, where x is a concrete type, e.g.
import Control.Exception
let f _ = putStrLn "error" :: SomeException -> IO ()
in handle f undefined
"Exception e" is likely from the type signature of "handle".
The documentation
says:
handle :: Exception e => (e -> IO a) -> IO a -> IO a
In GHC 6.8 it used to be different, which would explain why I don't get that error.
handle :: (Exception -> IO a) -> IO a -> IO a
Seems you're running into the monomorphism restriction. That "_"-Pattern must be monomorphic (which it is with ghc 6.8) or explicitly typed. A "workaround" is to put the pattern on the left hand side of a definition, where it constitutes a "simple pattern binding" as specified by the Haskell Report.
Try this:
let f _ = return "err"
handle f undefined
http://www.haskell.org/haskellwiki/Monomorphism_restriction

Resources