Here is one way to do this kind of work. There are many more cases to close if your fA fB has the type of variables in their intended types. In this case, the following code will have some pattern matching errors at compile time.
{-
It will even help you with the language that you compile in haskell, this is another question.
Added hints
If the type is polymorphic, you will see that reify gives something that does not apply to my sample code above.
> :set -XTemplateHaskell > :m +IPPrint Language.Haskell.TH > putStrLn $(reify 'id >>= stringE . pshow)
Prints out what describes (a-> a):
VarI GHC.Base.id (ForallT [PlainTV a_1627394484] [] (AppT (AppT ArrowT (VarT a_1627394484)) (VarT a_1627394484))) Nothing (Fixity 9 InfixL)
With a little work you can split this type into CxtQ and TypeQ this instance of D needs.
I don’t know how much sense it generates to generate (a-> b). You could go about replacing all type variables with unique ones, which is probably best done with something like Data.Generics.everywhereM, because Type data has many many constructors.
You will still have a problem that this is not true:
instance Func_f (a -> b) where f _ = id
This approach to getting (a-> b) may cause your program to crash:
instance Func_f (a -> b) where f _ = unsafeCoerce id
This approach allows the instance to choose when the types are different, but at some later point in the execution of ghc, you may fail if "a" and "b" cannot be the same.
instance (a~b) => Func_f (a->b) where f _ = unsafeCoerce id