A value of type T a
with a
different from Bool
can never have the form T1 x
(since that has only type T Bool
).
Hence, in such case, the T1 x
branch in the case
becomes inaccessible and can be ignored during type checking/inference.
More concretely: GADTs allow the type checker to assume type-level equations during pattern matching, and exploit such equations later on. When checking
f :: T a -> a -> a
f x y = case x of
T1 x -> True
T2 -> y
the type checker performs the following reasoning:
f :: T a -> a -> a
f x y = case x of
T1 x -> -- assume: a ~ Bool
True -- has type Bool, hence it has also type a
T2 -> -- assume: a~a (pointless)
y -- has type a
Thanks to GADTs, both branches of the case have type a
, hence the whole case expression has type a
and the function definition type checks.
More generally, when x :: T A
and the GADT constructor was defined as K :: ... -> T B
then, when type checking we can make the following assumption:
case x of
K ... -> -- assume: A ~ B
Note that A
and B
can be types involving type variables (as in a~Bool
above), so that allows one obtain useful information about them and exploit it later on.
T a -> Bool -> Bool
then the compiler won't allowf T2 1
and that's basically the difference? – Pless