Не удается отловить исключение, выданное «чистой» функцией - PullRequest
0 голосов
/ 25 марта 2019

Я пытаюсь поймать пользовательское исключение, выданное «чистым» кодом. Я не понимаю поведение моей программы.

Я использую 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 Ответ

3 голосов
/ 25 марта 2019

Из-за лени, foo 1 не будет выполнено, пока вы фактически не попытаетесь напечатать значение n. По сути, n привязан к неоцененному thunk 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...