如何捕获异常

时间:2015-10-11 01:36:27

标签: haskell error-handling

你如何处理Haskell中的错误?假设我有分裂功能。如果可以执行除法,则返回true,否则返回false。

di :: Int -> Bool
di a b = a `div` b

如何捕获此类场景中的异常,以便返回布尔值?如何捕获所有异常,而不仅仅是特定类型的异常?我知道我可以检查b是否为零,但我只是想知道错误处理。

更新: 这是我到目前为止所做的。但是我遇到类型不匹配错误。任何人都可以指出我如何解决这个问题?

di :: Int -> Int -> Bool
di a b = do
    result <- try (a `div` b) :: IO (Either SomeException Bool)
    case result of
       Left ex  -> False
       Right val -> True

错误

Couldn't match type ‘IO b0’ with ‘Bool’
Expected type: IO (Either SomeException Bool)
               -> (Either SomeException Bool -> IO b0) -> Bool
  Actual type: IO (Either SomeException Bool)
               -> (Either SomeException Bool -> IO b0) -> IO b0

1 个答案:

答案 0 :(得分:1)

您的代码存在一些问题:

  • di在IO monad中运行,因此结果类型必须为IO Bool
  • try需要进行IO计算,但div a b是纯值,因此您需要使用return来提升它。
  • 同样,di返回IO Bool,因此最后一个case语句需要return来将case表达式提升为IO计算。

这是di版本的类型检查:

di' :: Int -> Int -> IO Bool
di' a b = do
  r <- try (return (div a b)) :: IO (Either SomeException Int)
  return $ case r of
             Left _ -> False
             Right _ -> True

但是,此版本将为所有输入返回True。原因是由于延迟评估,div函数实际上从未被调用过。

解决此问题的一种方法是使用BangPatterns编译指示强制进行评估:

{-# LANGUAGE BangPatterns #-}

di' :: Int -> Int -> IO Bool
di' a b = do
  r <- try (let !x = div a b in return x) :: IO (Either SomeException Int)
  return $ case r of
            Left _ -> False
            Right _ -> True

ghci> di' 3 0
False

ghci> di' 3 1
True

另请参阅此SO问题:How to catch a divide by zero error in Haskell?,了解有关如何仅捕获算术异常的详细信息。