So there are many advantages of having typeclasses in C a Bool
form. Mostly because they let you do any logical operation between two constraints when the normal C a
just implicitly ANDs everything.
If we consider ~
a class constraint, this can be done like so
class Equal x y b | x y -> b
instance Equal x x True
instance False ~ b => Equal x y b
But what makes this case special is the fact that putting x x
in the head of the instance is equivalent to x ~ y =>
and then x y
in the head. This is not the case for any other typeclass.
So if we try to do something similar for a class C
we get something like
class C' x b | x -> b
instance C x => C' x True
instance False ~ Bool => C' x b
Unfortunately this doesn't work since only one of those instances will ever be picked because they don't discriminate on the type x
so any type matches both heads.
I've also read https://www.haskell.org/haskellwiki/GHC/AdvancedOverlap which again doesn't apply for any class C
because it requires you to rewrite all the instances of the original class. Ideally, I'd like my code to work with GHC.Exts.Constraint
and KindSignatures
so that C
can be parametric.
So, for a class like this
class Match (c :: * -> Constraint) x b | c x -> b
How do I write the instances so that Match c x True
if and only if c x
, Match c x False
otherwise?
C a Bool
form is stronger thanC a
. You are essentially asking how to collect the set of instances of a type class, which is impossible. – user2407038Match
. In module A I definedata X = X
, andclass A b x | b -> x; a :: Proxy b -> x; instance A True Int; instance A False Bool
,test :: forall x b y . (Match Eq x b, A b y) => x -> y; test _ = a (Proxy :: Proxy b)
. I have module B (imports A), in which the type oftest X
must beInt
. In module C (import A) I haveinstance Eq X
sotest X :: Bool
. Module D imports B and C. Module D can't can't force B and C to recompile, sotest X
must paradoxically have two types at once. – user2407038C
to a value". – user2407038