-- A solution, but it couples Entity to GetMessage import Data.Kind main :: IO () main = pure () -- making `a` the second variable data Entity (c :: Type -> Constraint) = forall a. (c a, GetMessage a) => MkEntity a class HasDataID a where getDependencies :: a -> Entity HasDataID instance HasDataID (Entity HasDataID) where getDependencies (MkEntity x) = getDependencies x data Foo = Foo Bar data Bar = Bar instance HasDataID Foo where getDependencies (Foo bar) = MkEntity bar class GetMessage a where getMessage :: Int -> a -> String instance GetMessage (Entity HasDataID) where getMessage int (MkEntity x) = getMessage int x instance GetMessage Foo where getMessage nr foo = "foo: " <> show nr instance HasDataID Bar where getDependencies bar = MkEntity $ Foo bar instance GetMessage Bar where getMessage nr bar = "bar: " <> show nr