IORef сохранение значения в случае ошибки
Есть ли способ НЕ изменять значение IORef, если ошибка происходит внутри modifyIORef
?
import Data.IORef
main = do
a <- newIORef (1::Int)
-- a keeps error now, not Int
modifyIORef a (const $ error "Error forever")
val <- readIORef a -- val is error now
putStrLn $ "Result: " ++ show val -- throws error
2 ответа
Я верю, что вы можете сделать это с modifyIORef'
или же atomicModifyIORef'
завернутый в обработчик исключений. Я не рекомендовал бы это вообще; error
вызовы создают строки для чтения пользователями, а не детальную информацию для обработчика. И весь механизм "неточных исключений" для обработки исключений, генерируемых из "чистого" кода, требует много внимания для правильного использования. Вам почти всегда лучше быть уверенным в том, что вы никогда не выбросите исключения из чистого кода. ExceptT
а также Either
и такое может помочь.
Haskell не выполняет обработку ошибок так же, как другие языки, такие как Python и Java. Когда вы звоните error
функция, программа остановится. Период. Ошибка не может быть поймана. Нет способа перенаправить его или перезапустить программу. error
Функция выдает ошибку, а не исключение. Если вы хотите представить идею неудачи в Haskell, вы используете Maybe
а также Either
монады. Ниже описано, как вы можете реализовать функциональность, которую вы хотите, используя Either
монада.
main = do
a <- NewIORef (Right 1 :: Either String Int)
modifyIORef a (const $ Left "some execution error")
-- a now holds a "Left" value, representing an error
val <- readIORef a
-- val now holds the "Left" value
case val of
Left err -> putStrLn $ "Error: " ++ err -- prints error (if applicable)
Right val -> putStrLn $ "Result: " ++ show val -- prints value (if applicable)
РЕДАКТИРОВАТЬ: Как dfeuer любезно указал в своем комментарии, возможно перехватить ошибки в GHC. Это, однако, считается плохой практикой, за исключением очень специфических обстоятельств, поэтому использование Maybe
а также Either
типы по-прежнему предпочтительнее.