我有一个功能
import System.Exit
exit_and_report_type_mismatch :: String -> IO ExitCode
exit_and_report_type_mismatch error_message = do
putStrLn error_message
exitFailure
和另一部分像这样
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向我抱怨它期待类型Val(我定义的另一种数据类型),但它实际上接收类型IO Exitcode。足够公平 - exit_and_report_mismatch正在返回IO ExitCode,它不是Val。
如何从“exit_and_report_type_mismatch”中完全中止Haskell程序?我已经阅读了一些关于Haskell异常的内容,但是解释要么没有意义,要么提到必须从main函数调用ExitWith,这不是一个选项。
答案 0 :(得分:10)
这是error
的用途。来自文档:
例如:
zsh% runhaskell <<<'main = putStrLn (error "Message") >> print "Not reached."'
runghcXXXX7729.hs: Message
putStrLn
的效果被忽略,一旦error
产生的值被要求,程序就会终止(延迟评估意味着只将error
放在某处并不会立即导致错误;正如您可能或可能不期望的那样,let x = error "Message" in putStrLn "Printed"
不会导致错误)。 可以使用Control.Exception.Base
中的函数捕获这些异常,例如catch
,但我从未这样做,也没有看到过这种情况。
另外,作为最后一点,请考虑避免使用error
。在可能的情况下,最好避免使用部分函数(未在整个输入域中定义的函数),因为使用总函数提供的更强保证更容易推理代码。如果对于总函数,f :: A -> B
实际上意味着“函数f
返回B
类型的东西”,这是很好的。对于部分函数,f :: A -> B
仅表示“如果函数f
返回,则它返回的类型为B
”。在您的情况下,这可能意味着具有类似interpretExpr :: Vars -> Expr -> Either RuntimeError Val
的类型,或者适合同构的类型(在最简单的情况下,可能是data Result = Error String | Value Val
和interpretExpr :: Vars -> Expr -> Result
)。
答案 1 :(得分:0)
这样做:
import System.IO.Unsafe
exit_and_report_type_mismatch :: String -> a
exit_and_report_type_mismatch error_message = unsafePerformIO $ do
putStrLn error_message
exitFailure
函数error可能会起作用。