{-# language ImpredicativeTypes, UndecidableSuperClasses #-} import Control.Monad.Reader.Class (MonadReader) import Control.Monad.IO.Class (MonadIO) newtype EffFun c m a = EffFun (c m => m a -> m a) class (c1 m, c2 m) => Combine c1 c2 m instance (c1 m, c2 m) => Combine c1 c2 m f :: f (forall m a. EffFun (MonadReader ()) m a) f = undefined g :: f (forall m a. EffFun (MonadIO) m a) g = undefined h1, h2, h3 :: Applicative f => f (forall m a. EffFun (Combine (MonadReader ()) MonadIO) m a) h1 = (\(EffFun f) (EffFun g) -> EffFun (f . g)) <$> f <*> g h2 = specialisedCompose <$> f <*> g where specialisedCompose :: (forall m a. EffFun (MonadReader ()) m a) -> (forall m a. EffFun (MonadIO) m a) -> forall m a. EffFun (Combine (MonadReader ()) MonadIO) m a specialisedCompose (EffFun f) (EffFun g) = EffFun (f . g) h3 = generalisedCompose <$> f <*> g where generalisedCompose :: (forall m a. EffFun c1 m a) -> (forall m a. EffFun c2 m a) -> (forall m a. EffFun (Combine c1 c2) m a) generalisedCompose f' g' = EffFun (case (f', g') of (EffFun f, EffFun g) -> f . g) main = putStrLn "hello"