{-|
Module      : DeepControl.Monad.Maybe
Description : 
Copyright   : (c) 2007 Yitzak Gale, Eric Kidd,
              (C) 2015 KONISHI Yohsuke
License     : BSD-style (see the file LICENSE)
Maintainer  : ocean0yohsuke@gmail.com
Stability   : experimental
Portability : ---

This module is just a concise mimic for Maybe Monad in mtl(monad-transformer-library).
The qualifier "concise" means that this module doesn't make no attempt to transform functions of any kind of Monad automatically.
So when making some new data type of MaybeT, you have to manually define involved Monad instances, 
for example `DeepControl.Monad.MonadReader`, `DeepControl.Monad.MonadWriter` or `DeepControl.Monad.MonadState`, 
by making use of the transformation functions such as `trans`, `trans2`, etc.
Admittedly it is tedious though, you can deeply understand monad-transformation mechanism instead.
-}
module DeepControl.Monad.Maybe (

    -- * Level-1
    MaybeT(..), mapMaybeT, liftCatch,

    ) where 

import DeepControl.Applicative
import DeepControl.Monad
import DeepControl.MonadTrans
import DeepControl.Commutative

import Control.Monad.Signatures

----------------------------------------------------------------------
-- Level-1

newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }

instance (Functor m) => Functor (MaybeT m) where
    fmap f mv = MaybeT $ f |$>> runMaybeT mv
instance (Monad m) => Applicative (MaybeT m) where
    pure = MaybeT . (**:)
    f <*> v = MaybeT $ runMaybeT f |*>> runMaybeT v
instance (Monad m) => Monad (MaybeT m) where
    return = pure
    mv >>= f = MaybeT $ 
        runMaybeT mv >>== \v -> 
        runMaybeT (f v)

instance MonadTrans MaybeT where
    trans = MaybeT . (-*) 
instance (MonadIO m) => MonadIO (MaybeT m) where
    liftIO = trans . liftIO

mapMaybeT :: (m (Maybe a) -> n (Maybe b)) -> MaybeT m a -> MaybeT n b
mapMaybeT f = MaybeT . f . runMaybeT

liftCatch :: Catch e m (Maybe a) -> Catch e (MaybeT m) a
liftCatch catchE m h = MaybeT $ runMaybeT m `catchE` \e -> runMaybeT (h e)