The idea of representing a class by data type is basically a dictionary, which is actually largely related to how the GHC implements class classes anyway: a boundedly polymorphic function / value
f :: Functor f => Y
is at run time represented by function
_f_ :: FunctorDict f -> Y
where FunctorDictessentially your FunctorRank2-ADT (or GADT).
, , , singleton: F instance Functor F, FunctorDict F . , , (GHC , ), .