{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-} module TestTryAny where import Control.Applicative (Alternative, empty, (<|>)) import Control.Exception (Exception, fromException, throwIO) import Control.Exception.Enclosed (tryAny, catchAny) import Control.Monad.Base (MonadBase) import Control.Monad.IO.Class (MonadIO, liftIO) import Control.Monad.Trans.Control (MonadBaseControl, StM, liftBaseWith, restoreM) import Control.Monad.Trans.Resource () import Data.Typeable (Typeable) -- Explore tryAny behavior, transformers and MonadBaseControl data IOAlternativeEmpty = IOAlternativeEmpty deriving (Typeable, Show) instance Exception IOAlternativeEmpty newtype MyIO a = MyIO { runMyIO :: IO a } deriving (Functor, Applicative, Monad, MonadIO, MonadBase IO) instance MonadBaseControl IO MyIO where type StM MyIO a = a liftBaseWith f = liftIO $ f runMyIO restoreM = return {-# INLINABLE liftBaseWith #-} {-# INLINABLE restoreM #-} instance Alternative MyIO where empty = liftIO $ throwIO IOAlternativeEmpty x <|> y = x `catchAny` \xe -> y `catchAny` \ye -> case fromException ye of Just IOAlternativeEmpty -> liftIO $ throwIO xe _ -> liftIO $ throwIO ye testThis :: IO () testThis = runMyIO $ liftIO $ do print =<< tryAny (putStrLn "one" <|> putStrLn "two") print =<< tryAny (error "oops" <|> putStrLn "two") print =<< tryAny (error "oops" <|> error "here" :: IO ()) print =<< tryAny (putStrLn "one" <|> empty) print =<< tryAny (empty <|> putStrLn "two") print =<< tryAny (empty <|> empty :: IO ()) print =<< tryAny (error "oops" <|> empty :: IO ()) print =<< tryAny (empty <|> error "here" :: IO ())