module Buffet.Toolbox.ExceptionTools ( eitherThrow , sequenceAccumulatingExceptions ) where import qualified Control.Exception as Exception import qualified Data.Either as Either import qualified Data.Foldable as Foldable import qualified Data.List.NonEmpty as NonEmpty import Prelude ( Either , IO , Show , Traversable , ($) , (.) , (>>=) , either , fmap , maybe , pure , show , traverse , undefined , unlines ) newtype ExceptionList = ExceptionList (NonEmpty.NonEmpty Exception.SomeException) instance Show ExceptionList where show (ExceptionList exceptions) = unlines . NonEmpty.toList $ fmap show exceptions instance Exception.Exception ExceptionList eitherThrow :: Exception.Exception e => (a -> e) -> IO (Either a b) -> IO b eitherThrow toException = (>>= either (Exception.throwIO . toException) pure) sequenceAccumulatingExceptions :: Traversable t => t (IO a) -> IO (t a) sequenceAccumulatingExceptions actions = do results <- traverse Exception.try actions let successes = fmap (Either.fromRight undefined) results failures = Either.lefts $ Foldable.toList results maybe (pure successes) (Exception.throwIO . ExceptionList) $ NonEmpty.nonEmpty failures