{-# LANGUAGE PackageImports #-} module NatTrans where import "base" Data.Functor.Identity import "transformers" Control.Monad.Trans.Class import "transformers" Control.Monad.Trans.State -- actually from mmorph class MFunctor t where hoist :: (Monad m) => (forall a . m a -> n a) -> t m b -> t n b class Embeds m n where embed :: m a -> n a instance Embeds m m where embed :: m a -> m a embed = id instance (Applicative m) => Embeds Identity m where embed :: Identity a -> m a embed = pure . runIdentity -- if @m@ is a `Monad` and @t@ is a `MonadTrans`, then `Embeds n m` implies `Embeds n (t m)` instance {-# OVERLAPPABLE #-} (Monad m, MonadTrans t, Embeds n m) => Embeds n (t m) where embed :: n a -> (t m) a embed = lift . embed -- if @n@ is a `Monad` and @t@ is a `MFunctor`, then `Embeds n m` implies `Embeds (t n) (t m)` instance {-# OVERLAPPING #-} (Monad n, MFunctor t, Embeds n m) => Embeds (t n) (t m) where embed :: t n a -> t m a embed = hoist embed ioOperation :: IO () ioOperation = print "hello!" statefulOperation :: State Int () statefulOperation = state (\i -> ((), i + 1)) combineTheTwo :: StateT Int IO () combineTheTwo = do embed ioOperation embed statefulOperation