无法捕获“纯”函数引发的异常

时间:2019-03-25 15:33:38

标签: haskell exception

我正在尝试捕获“纯”代码引发的自定义异常。我不了解我的程序的行为。

我正在使用GHC 8.6.3。这是我的代码:

import Control.Exception

newtype Problem = Problem String deriving Show

instance Exception Problem

foo :: Int -> Int
foo n = n + (throw $ Problem "Whoops")

baz :: IO Int
baz =
  return (foo 1)
  `catch` \(Problem _) -> return 100

main = do
  n <- baz
  print n
  `catch` \(Problem msg) -> putStrLn msg

我希望第一个处理程序捕获异常,并使程序打印“ 100”。相反,它被第二个处理程序捕获并显示“ Whoops”。

为什么在main中而不是在baz中捕获了异常?如何在baz中捕获异常?

1 个答案:

答案 0 :(得分:3)

由于懒惰,foo 1直到您实际尝试打印n的值时才会执行。本质上,n绑定到未经评估的重击foo 1,而不是foo 1的结果。

强制baz处理异常的一种比较笨拙的方法是使用seq;几乎肯定会有一个更优雅的解决方案。

baz = let result = foo 1
      in seq result (return result) `catch` \(Problem msg) -> return 100

而且,感谢@Alec,更优雅的解决方案是在原始函数中将return替换为Control.Exception.evaluate

baz :: IO Int
baz =
  evaluate (foo 1)
  `catch` \(Problem _) -> return 100