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
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With