Define eta-expanded EtaReaderT and EtaStateT types, derive all other monads `via` it
newtype IOEnv env a = IOEnv' (env -> IO a)
deriving (Functor)
deriving (MonadThrow, MonadCatch, MonadMask, MonadIO) via (ReaderT env IO)
-- See Note [The one-shot state monad trick] in GHC.Utils.Monad
pattern IOEnv :: forall env a. (env -> IO a) -> IOEnv env a
pattern IOEnv m <- IOEnv' m
where
IOEnv m = IOEnv' (oneShot m)
{-# COMPLETE IOEnv #-}
It's nice that we get by with so little code to derive all the Monad stuff that we need. But it also renders Note [The one-shot state monad trick]
ineffective! That Note even says today
Derived instances
~~~~~~~~~~~~~~~~~
One caveat of both approaches is that derived instances don't use the smart
constructor /or/ the pattern synonym. So they won't benefit from the automatic
insertion of "oneShot".
data M a = MkM' (State -> (State,a))
deriving (Functor) <-- Functor implementation will use MkM'!
Conclusion: don't use 'deriving' in these cases.
It follows that none of the derived instances above go through the oneShot
pattern synonym.
Given that we basically use IOEnv
everywhere, that probably leaves a lot of performance on the table.
It appears we need the code bloat of writing all those functions ourselves for now. And while we are writing out all those functions, why not making sure that we do so exactly once and then -XDerivingVia
all the other instances?
I propose to copy three modules from transformers
, Control.Monad.Trans.State.Strict
(or maybe C.M.T.S.Lazy, to keep the current semantics), Control.Monad.Trans.Reader
and Control.Monad.Trans.RWS.CPS
(which we could use for FCode
and in StgLiftLams) to the GHC code base as EtaStateT
, EtaReaderT
and EtaRWST
and give them the Note [The one-shot state monad trick]
treatment. Same interface, but everything is eta-expanded by default. Then derivevia all GHC monads. That way we can't forget (and don't need to) to write the monad instances ourselves and can be sure that everything eta-expands.
There is a reasonable chance that transformers
merges those modules or variants thereof upstream (https://hub.darcs.net/ross/transformers/issue/79).