I have a class
class Monad m => MyClass m where
type MyType1 m
type MyType2 m
...
a :: m (MyType1 m)
b :: m (MyType2 m)
c :: m (MyType3 m)
...
and I also have bunch of instances that implement the functions (a
... ) reasonably
instance MyClass A where
type MyType1 A = Int
...
a = ...
...
instance MyClass (B a) where
type MyType1 (B a) = Char
...
a = ...
...
...
but I also have a lot of instances that don't do anything useful apart from lifting the implementation through transformers:
instance MyClass m => MyClass (MyTransA m)
type MyType1 (MyTransA m) = MyType1 m
...
a = lift a
...
instance MyClass m => MyClass (MyTransB m)
type MyType1 (MyTransB m) = MyType1 m
...
a = lift a
...
...
and this turns out to be a lot of boilerplate to write, so I wanted to replace these repetitive uninteresting instances with simply
class MonadTrans t => AutoLiftMyClass t
instance (AutoLiftMyClass a, MyClass m) => MyClass (a m)
type MyType1 (a m) = MyType1 m
...
a = lift a
...
which would allow me to write only
instance AutoLiftMyClass MyTransA
instance AutoLiftMyClass MyTransB
...
to get the lifting for free, avoiding the enumeration of all the lifted a
, b
, ... for every MyTransA
, MyTransB
, ...
The problem is that for whatever reason (I really don't know why) GHC considers only the RHS of instance declarations, thus my AutoLiftMyClass
collides on type family instances for MyType1
, ... with all the reasonable instances A
, B
, ... (those that don't declare an instance of AutoLiftMyClass
)
I have seen some posts and articles on wiki about closed type families but they do not make much sense to me. Is there any way how to make this idea work?