To "more directly" do the same thing as in coq, you can also take the singletons approach, and either explicitly use a "proof providing" function:
withC :: STag t -> (C (Foo t) => r) -> r
withC tag k =
case tag of
SA -> k
SB -> k
(so if you call `withC tag body` you now have the required constraint in `body`
or you could use the implicit singleton carrying type class:
instance STagI t => C (Foo t) where
f =
case tagSing of
SA -> f
SB -> f
and the remaining boilerplate code required:
data STag t where
SA :: STag A
SB :: STag B
class STagI t where
tagSing :: STag t
instance STag A where
tagSing = SA
instance STag B where
tagSing = SB