When the GADTs extension is enabled, besides regular data declarations, you can also declare generalized algebraic datatypes as follows:
data DataType a where
Constr1 :: Int -> a -> Foo a -> DataType a
Constr2 :: Show a => a -> DataType a
Constr3 :: DataType Int
A GADT declaration lists the types of all constructors a datatype has, explicitly. Unlike regular datatype declarations, the type of a constructor can be any N-ary (including nullary) function that ultimately results in the datatype applied to some arguments.
In this case we've declared that the type DataType has three constructors: Constr1, Constr2 and Constr3.
The Constr1 constructor is no different from one declared using a regular data declaration: data DataType a = Constr1 Int a (Foo a) | ...
Constr2 however requires that a has an instance of Show, and so when using the constructor the instance would need to exist. On the other hand, when pattern-matching on it, the fact that a is an instance of Show comes into scope, so you can write:
foo :: DataType a -> String
foo val = case val of
Constr2 x -> show x
...
Note that the Show a constraint doesn't appear in the type of the function, and is only visible in the code to the right of ->.
Constr3 has type DataType Int, which means that whenever a value of type DataType a is a Constr3, it is known that a ~ Int. This information, too, can be recovered with a pattern match.