module Control.Monad.Task.Class 
  ( 
    MonadTask(..)
  , orElse
  ) where
import Data.Monoid
import Control.Monad.Cont
import Control.Monad.Trans.Identity
import Control.Monad.Trans.List
import Control.Monad.Trans.Maybe
import Control.Monad.Trans.Reader
import qualified Control.Monad.Trans.Writer.Lazy as LazyWriter
import qualified Control.Monad.Trans.Writer.Strict as StrictWriter
import Control.Monad.Trans.Except
class Monad m => MonadTask e m | m -> e where
  
  yield  :: m ()
  
  
  fork   :: m a -> m ()
  
  
  watch  :: (e -> Maybe a) -> m a
  
  
  signal :: e -> m ()
  
  exit   :: m ()
orElse :: (e -> Maybe a) -> (e -> Maybe b) -> e -> Maybe (Either a b)
orElse f g x = maybe (fmap Right (g x)) (Just . Left) (f x)
instance (Monad m, MonadTask a m) => MonadTask a (ExceptT e m) where
  exit   = lift exit
  yield  = lift yield
  fork   = lift . fork . runExceptT
  watch  = lift . watch
  signal = lift . signal
instance (Monad m, MonadTask a m) => MonadTask a (IdentityT m) where
  exit   = lift exit
  yield  = lift yield
  fork   = lift . fork . runIdentityT 
  watch  = lift . watch
  signal = lift . signal
instance (Monad m, MonadTask a m) => MonadTask a (ListT m) where
  exit   = lift exit
  yield  = lift yield
  fork   = lift . fork . runListT 
  watch  = lift . watch
  signal = lift . signal
instance (Monad m, MonadTask a m) => MonadTask a (MaybeT m) where
  exit   = lift exit
  yield  = lift yield
  fork   = lift . fork . runMaybeT 
  watch  = lift . watch
  signal = lift . signal
instance (Monad m, MonadTask a m) => MonadTask a (ReaderT r m) where
  exit   = lift exit
  yield  = lift yield
  fork   = ReaderT . (fork .) . runReaderT 
  watch  = lift . watch
  signal = lift . signal
instance (Monoid w, Monad m, MonadTask a m) => MonadTask a (LazyWriter.WriterT w m) where
  exit   = lift exit
  yield  = lift yield
  fork   = lift . fork . LazyWriter.runWriterT 
  watch  = lift . watch
  signal = lift . signal
instance (Monoid w, Monad m, MonadTask a m) => MonadTask a (StrictWriter.WriterT w m) where
  exit   = lift exit
  yield  = lift yield
  fork   = lift . fork . StrictWriter.runWriterT 
  watch  = lift . watch
  signal = lift . signal