Haskell中异常处理 [英] Exception handling in Haskell

查看:243
本文介绍了Haskell中异常处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要帮助了解三个Haskell函数的使用情况。

I need help to understand the usage of the three Haskell functions


  • try( Control.Exception.try :: Exception e => IO a - > IO(EEA)

  • catch( Control.Exception.catch: :Exception e => IO a - >(e - > IO a) - > IO a

  • 句柄( Control.Exception.handle :: Exception e =>(e - > IO a) - > IO a - > IO a

  • try (Control.Exception.try :: Exception e => IO a -> IO (Either e a))
  • catch (Control.Exception.catch :: Exception e => IO a -> (e -> IO a) -> IO a)
  • handle (Control.Exception.handle :: Exception e => (e -> IO a) -> IO a -> IO a)

我需要知道几件事情:


  1. 什么时候使用哪个功能? li>
  2. 如何使用这个功能一些简单的例子?

  3. catch和handle之间有什么区别?他们的签名只有不同的顺序。

我会尝试写下我的试验,希望你能帮助我:

I will try to write down my trials and hope you can help me:

尝试

我有一个例子:

x = 5 `div` 0
test = try (print x) :: IO (Either SomeException ())

我有两个问题:


  1. 如何设置自定义错误输出?

  1. How can I set a custom error output?

我可以做什么来将所有错误设置为SomeException,所以我不必写 :: IO(SomeException())

What can i do to set all errors to SomeException so I dont must write the :: IO (Either SomeException())

catch /尝试

你能给我一个自定义错误输出的简短示例吗?

Can you show me a short example with a custom error output?

推荐答案

什么时候使用哪个函数?



这是Control.Exception文档中的建议:

When do I use which function?

Here's the recommendation from the Control.Exception documentation:


  • 如果你想在一个例外的情况下做一些清理on被提升,最终使用 括号 onException

  • 要在异常后恢复并执行其他操作,最好的选择是使用尝试家族之一。

  • ...除非您正在从异步异常中恢复,否则使用 catch catchJust

  • If you want to do some cleanup in the event that an exception is raised, use finally, bracket or onException.
  • To recover after an exception and do something else, the best choice is to use one of the try family.
  • ... unless you are recovering from an asynchronous exception, in which case use catch or catchJust.

尝试采取 IO 操作运行,并返回一个。如果计算成功,结果将被包含在 Right 构造函数中。 (认为​​对,而不是错)。如果该操作抛出了指定类型的异常,则返回 Left 构造函数。如果异常是不是的适当类型,它将继续向上传播堆栈。指定 SomeException 作为类型将捕获所有异常,这可能是也可能不是一个好主意。

try takes an IO action to run, and returns an Either. If the computation succeeded, the result is given wrapped in a Right constructor. (Think right as opposed to wrong). If the action threw an exception of the specified type, it is returned in a Left constructor. If the exception was not of the appropriate type, it continues to propagate up the stack. Specifying SomeException as the type will catch all exceptions, which may or may not be a good idea.

请注意如果要从纯粹的计算中捕获异常,则必须使用评估来强制评估 try

Note that if you want to catch an exception from a pure computation, you will have to use evaluate to force evaluation within the try.

main = do
    result <- try (evaluate (5 `div` 0)) :: IO (Either SomeException Int)
    case result of
        Left ex  -> putStrLn $ "Caught exception: " ++ show ex
        Right val -> putStrLn $ "The answer was: " ++ show val



catch :: Exception e => IO a - >(e - > IO a) - > IO a



catch 类似于尝试。它首先尝试运行指定的 IO 操作,但是如果抛出异常,则处理程序将给出异常以获取其他答案。

catch :: Exception e => IO a -> (e -> IO a) -> IO a

catch is similar to try. It first tries to run the specified IO action, but if an exception is thrown the handler is given the exception to get an alternative answer.

main = catch (print $ 5 `div` 0) handler
  where
    handler :: SomeException -> IO ()
    handler ex = putStrLn $ "Caught exception: " ++ show ex

但是,有一个重要的区别。当使用 catch 时,您的处理程序不能被异步异常中断(即通过 throwTo 从另一个线程抛出)。尝试提出异步异常将阻塞,直到您的处理程序运行完毕。

However, there is one important difference. When using catch your handler cannot be interrupted by an asynchroneous exception (i.e. thrown from another thread via throwTo). Attempts to raise an asynchroneous exception will block until your handler has finished running.

请注意,有一个不同的 catch 在前奏中,所以你可能想做 import Prelude hiding(catch)

Note that there is a different catch in the Prelude, so you might want to do import Prelude hiding (catch).

handle 只是 catch 以相反的顺序使用参数。使用哪一个取决于什么使您的代码更易于阅读,如果您想要使用部分应用程序,哪个更适合您。

handle is simply catch with the arguments in the reversed order. Which one to use depends on what makes your code more readable, or which one fits better if you want to use partial application. They are otherwise identical.

请注意, try catch handle 将捕获指定的所有异常/推断类型。 tryJust 和朋友允许您指定一个选择器函数,以过滤出您特别想要处理的异常。例如,所有算术错误的类型为$ code> ArithException 。如果您只想抓住 DivideByZero ,可以执行以下操作:

Note that try, catch and handle will catch all exceptions of the specified/inferred type. tryJust and friends allow you to specify a selector function which filters out which exceptions you specifically want to handle. For example, all arithmetic errors are of type ArithException. If you only want to catch DivideByZero, you can do:

main = do
    result <- tryJust selectDivByZero (evaluate $ 5 `div` 0)
    case result of
        Left what -> putStrLn $ "Division by " ++ what
        Right val -> putStrLn $ "The answer was: " ++ show val
  where
    selectDivByZero :: ArithException -> Maybe String
    selectDivByZero DivideByZero = Just "zero"
    selectDivByZero _ = Nothing






关于纯度的注释



请注意,这种类型的异常处理只能在不纯的代码中发生(即 IO monad)。如果您需要处理纯代码中的错误,您应该使用可能而不是(或某些其他代数数据类型)。这通常是更好的,因为它更明确,所以你总是知道什么可以发生在哪里。像 Control.Monad.Error 这样的Monads使这种类型的错误处理更容易使用。


A note on purity

Note that this type of exception handling can only happen in impure code (i.e. the IO monad). If you need to handle errors in pure code, you should look into returning values using Maybe or Either instead (or some other algebraic datatype). This is often preferable as it's more explicit so you always know what can happen where. Monads like Control.Monad.Error makes this type of error handling easier to work with.

另请参见:

  • Control.Exception

这篇关于Haskell中异常处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆