{-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable #-} {-# OPTIONS_GHC -fno-warn-orphans #-} {-| 'IO' as 'Alternative' instance. If the left 'IO' monad of ('<|>') causes an error or 'goNext' is used, the right 'IO' monad is executed. Of course, side effects cannot be rolled back. This means that this 'Alternative' instance breaks the 'Alternative' laws. But it's common in parsers. -} module Data.Alternative.IO where import Control.Applicative import Control.Exception import Data.Typeable import Prelude hiding (catch) ---------------------------------------------------------------- instance Alternative IO where empty = goNext x <|> y = x `catch` (\(_ :: SomeException) -> y) ---------------------------------------------------------------- {-| Go to the next 'IO' monad by throwing 'AltIOgoNext'. -} goNext :: IO a goNext = throwIO AltIOgoNext {-| Run any one 'IO' monad. -} runAnyOne :: [IO a] -> IO a runAnyOne = foldr (<|>) goNext ---------------------------------------------------------------- {-| Exception to control 'Alternative' 'IO'. -} data AltIOgoNext = AltIOgoNext deriving (Show, Typeable) instance Exception AltIOgoNext