`defaultLiftWith2` broken with ghc-9.0.1
Opened this issue · 4 comments
Older ghc versions are working, but with ghc 9.0.1 this fails:
https://travis-ci.com/github/jumper149/blucontrol/jobs/499404592#L486
src/Blucontrol/Recolor/X.hs:36:14: error:
• Couldn't match type: Monad (ReaderT Display m1)
with: RecolorXT m1 b
Expected: (Run RecolorXT -> m a) -> RecolorXT m a
Actual: (RunDefault2 RecolorXT (ExceptT XError) (ReaderT Display)
-> m a)
-> RecolorXT m a
• In the expression: defaultLiftWith2 RecolorXT unRecolorXT
In an equation for ‘liftWith’:
liftWith = defaultLiftWith2 RecolorXT unRecolorXT
In the instance declaration for ‘MonadTransControl RecolorXT’
|
36 | liftWith = defaultLiftWith2 RecolorXT unRecolorXT
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The source code is here:
https://github.com/jumper149/blucontrol/blob/v0.3.0.0/src/Blucontrol/Recolor/X.hs#L36
newtype RecolorXT m a = RecolorXT { unRecolorXT :: ExceptT XError (ReaderT Display m) a }
deriving (Applicative, Functor, Monad, MonadBase b, MonadBaseControl b, MonadError XError)
instance MonadTrans RecolorXT where
lift = RecolorXT . lift . lift
instance MonadTransControl RecolorXT where
type StT RecolorXT a = StT (ReaderT Display) (StT (ExceptT XError) a)
liftWith = defaultLiftWith2 RecolorXT unRecolorXT
restoreT = defaultRestoreT2 RecolorXT
I just came up with a way to reduce boilerplate a little!
First we set up a newtype, which will need an explicit implementation.
newtype CombinerT (t1 :: (Type -> Type) -> Type -> Type) (t2 :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) (a :: Type) = CombinerT { unCombinerT :: t1 (t2 m) a }
deriving (Applicative, Functor, Monad, MonadBase b, MonadBaseControl b)
instance ((forall m. Monad m => Monad (t2 m)), MonadTrans t1, MonadTrans t2) => MonadTrans (CombinerT t1 t2) where
lift = CombinerT . lift . lift
instance ((forall m. Monad m => Monad (t2 m)), MonadTransControl t1, MonadTransControl t2) => MonadTransControl (CombinerT t1 t2) where
type StT (CombinerT t1 t2) a = StT t2 (StT t1 a)
liftWith f = CombinerT $ liftWith $ \run -> liftWith $ \run' -> f $ run' . run . unCombinerT
restoreT = defaultRestoreT2 CombinerT
Then we can use DerivingVia
to keep it concise.
newtype RecolorXT m a = RecolorXT { unRecolorXT :: ExceptT XError (ReaderT Display m) a }
deriving (Applicative, Functor, Monad, MonadBase b, MonadBaseControl b, MonadError XError)
deriving (MonadTrans, MonadTransControl) via CombinerT (ExceptT XError) (ReaderT Display)
Another advantage of this method is, that it isn't even necessary to manually set StT RecolorR a
.
This was my inspiration: https://www.youtube.com/watch?v=UZaQuSIrO6s
Soooo, after spending some time on IRC...
there is also a way to use defaultLiftWith2
with GHC 9.
liftWith f = defaultLiftWith2 RecolorXT unRecolorXT $ \ x -> f x
Your combiner is ComposeT
, which we will (be able to define) with next release of transformers
.
The eta-expansion in #52 (comment) is the way to go. I'm quite sure we cannot do better, unfortunately. This is an effect of simplified subsumption.