This isn't an answer, but it's way too big for a comment. We can write
{-# LANGUAGE GeneralizedNewtypeDeriving
, DeriveFunctor #-}
import Control.Monad.Free
-- All the IO primops you could ever need
data IOF a = PutStrLn String a
| GetLine (String -> a)
deriving Functor
newtype MyIO a = MyIO {unMyIO :: Free IOF a}
deriving (Functor, Applicative, Monad)
But we can actually make a monad transformer out of this:
import Control.Monad.Trans.Free
newtype IOT m a = IOT {unIOT :: FreeT IOF m a}
deriving (Functor, Applicative, Monad, MonadTrans)
So I don't really think even IO
is excluded, although the isomorphism in that case is not "internal".