Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why GADT/existential data constructors cannot be used in lazy patterns?

Today, I got a compiler error when trying to use a lazy pattern when matching on an existential GADT constructor:

An existential or GADT data constructor cannot be used inside a lazy (~) pattern

Why is that limitation? What "bad" stuff could happen, if it were allowed?

like image 716
Petr Avatar asked Jan 26 '13 15:01

Petr


2 Answers

Consider

data EQ a b where   Refl :: EQ a a 

If we could define

transport :: Eq a b -> a -> b transport ~Refl a = a 

then we could have

transport undefined :: a -> b 

and thus acquire

transport undefined True = True :: Int -> Int 

and then a crash, rather than the more graceful failure you get when trying to head-normalise the undefined.

GADT data represent evidence about types, so bogus GADT data threaten type safety. It is necessary to be strict with them to validate that evidence: you can't trust unevaluated computations in the presence of bottom.

like image 180
pigworker Avatar answered Oct 21 '22 08:10

pigworker


With "normal" data, you can skip checking the constructor during pattern-matching, on the understanding that when you try to use the data from the pattern, it might turn out to not exist, thus throwing an exception at you.

With a GADT, the type signature potentially changes depending on which constructor is present. We need to know about types at compile-time; it's no good not checking the constructor until you need the values. If you do, you might have a type mismatch error. And that, potentially, means your program crashing with a segmentation fault (or worse). Haskell programs should never segfault.

like image 38
MathematicalOrchid Avatar answered Oct 21 '22 09:10

MathematicalOrchid