Важной особенностью исключений является то, что если действие IO a
выдает исключение, вы не получите никакого результирующего значения a
.Поскольку оператор связывания (>>=) :: Monad m => m a -> (a -> m b) -> m b
монад позволяет последующим действиям зависеть от результатов более ранних, это означает, что мы не можем выполнить следующие действия, если одно из них завершилось неудачей.можно использовать подход рампиона .Однако из вашего примера кажется, что вы заботитесь только о последовательности независимых действий с помощью оператора (>>)
.Вы можете сделать моноид из этого, но я думаю, что самый простой подход - это просто иметь функцию, которая запускает список IO ()
действий и собирает любые исключения в списке:
import Control.Exception (SomeException, try)
import Data.Either (lefts)
exceptions :: [IO ()] -> IO [SomeException]
exceptions = fmap lefts . mapM try
Вы будетенеобходимо использовать список действий вместо do
, хотя:
> :{
| exceptions [ putStrLn "foo"
| , throwIO DivideByZero
| , putStrLn "bar"
| , throwIO (IndexOutOfBounds "xyzzy")
| ]
| :}
foo
bar
[divide by zero,array index out of range: xyzzy]