{-# LANGUAGE TypeFamilies #-} class A a where type Id a check :: a -> Bool class B a where data PhantomData a = PhantomData data Test s t = Test { s :: s, phantom :: PhantomData t } class C a where data State a bar :: State a -> a -> a -> a data X = X1 | X2 deriving Show instance C X where data State X = forall s t . (A s, B t) => XState (Test s t) bar (XState st) a b = if check (s st) then a else b instance A Int where type Id Int = () check 0 = True check _ = False instance A String where type Id String = () check "" = True check _ = False instance B () data Y = Y1 | Y2 deriving Show instance C Y where data State Y = YState bar YState a b = a main = do let t1 = Test (0 :: Int) (PhantomData :: PhantomData ()) print $ bar (XState t1) X1 X2 let t2 = Test ("Hi" :: String) (PhantomData :: PhantomData ()) print $ bar (XState t2) X1 X2 print $ bar YState Y1 Y2