module Control.Monad.Gen
( GenT
, Gen
, module Control.Monad.Gen.Class
, runGenT
, runGen
, runGenTWith
, runGenWith) where
#if MIN_VERSION_mtl(2, 2, 1)
import Control.Monad.Except
#else
import Control.Monad.Error
#endif
import Control.Applicative
import Control.Monad.Identity
import Control.Monad.Cont.Class
import Control.Monad.Reader.Class
import Control.Monad.State
import Control.Monad.Writer.Class
import Control.Monad.Gen.Class
newtype GenT e m a = GenT {unGenT :: StateT e m a}
deriving(Functor)
instance (Monad m, Enum e) => MonadGen e (GenT e m) where
gen = GenT (modify succ) >> GenT get
instance Monad m => Monad (GenT e m) where
return = GenT . return
(GenT m) >>= f = GenT $ m >>= unGenT . f
instance (Functor f, Monad f) => Applicative (GenT e f) where
pure = GenT . pure
(GenT f) <*> (GenT a) = GenT $ f <*> a
instance (Monad m, Functor m, MonadPlus m) => Alternative (GenT e m) where
empty = mzero
(<|>) = mplus
type Gen e = GenT e Identity
instance MonadTrans (GenT e) where
lift = GenT . lift
instance MonadReader r m => MonadReader r (GenT e m) where
local f = GenT . local f . unGenT
ask = GenT ask
instance MonadState s m => MonadState s (GenT e m) where
get = GenT $ lift get
put = GenT . lift . put
instance (MonadWriter w m) => MonadWriter w (GenT e m) where
tell m = lift $ tell m
listen = GenT . listen . unGenT
pass = GenT . pass . unGenT
instance MonadFix m => MonadFix (GenT e m) where
mfix = GenT . mfix . (unGenT .)
instance MonadPlus m => MonadPlus (GenT e m) where
mzero = GenT mzero
mplus (GenT m) (GenT m') = GenT $ mplus m m'
instance MonadIO m => MonadIO (GenT e m) where
liftIO = GenT . liftIO
instance MonadCont m => MonadCont (GenT e m) where
callCC f = GenT $ callCC (unGenT . f . (GenT .))
#if MIN_VERSION_mtl(2, 2, 1)
#else
instance MonadError e m => MonadError e (GenT e' m) where
throwError = GenT . throwError
catchError m h = GenT $ catchError (unGenT m) (unGenT . h)
#endif
runGenT :: (Enum e, Monad m) => GenT e m a -> m a
runGenT = runGenTWith (toEnum 0)
runGen :: Enum e => Gen e a -> a
runGen = runGenWith (toEnum 0)
runGenTWith :: Monad m => e -> GenT e m a -> m a
runGenTWith e = flip evalStateT e . unGenT
runGenWith :: e -> Gen e a -> a
runGenWith e = runIdentity . runGenTWith e