I want to write something similar to the following:
newtype FooT c d m a = FooT { unFooT :: (c (d m)) a }
instance (MonadTrans c, MonadTrans d) => MonadTrans (FooT c d) where
lift = FooT . lift . lift
However, this snippet will not compile:
Could not deduce (Monad (d m)) arising from a use of ‘lift’
I understand why this won't compile; we don't know that the application of an arbitrary transformer d m is itself a monad. However, I'm not sure of the best way to proceed.
Is there a clean way to make something like this work? Presumably it would go through if I could add a constraint along the lines of Monad (d m) to the left-hand-side of the instance declaration, but I don't know how to do so since m is not bound.
CodePudding user response:
With the QuantifiedConstraints GHC extension, this is
{-# LANGUAGE QuantifiedConstraints #-}
instance (MonadTrans c, MonadTrans d, forall m. Monad m => Monad (d m)) =>
MonadTrans (FooT c d) where
lift = FooT . lift . lift
m in the constraint is not the same m as in lift. The quantified constraint simply means what it says ("for any m :: Type -> Type, if Monad m require Monad (d m)"), and in lift that universal statement is being instantiated with the particular m being passed as argument to lift. Thus lift's m does not escape its scope.
