In a GADT, the product constructors can provide an explicit instantiation of the ADT as the type instantiation of their return value. This allows defining functions with a more advanced type behaviour. For a data constructor of Haskell 2010, the return value has the type instantiation implied by the instantiation of the ADT parameters at the constructor's application. -- A parametric ADT that is not a GADT data List a = Nil | Cons a integers = Cons 12 -- the type of integers is List Int strings = Cons "boat" -- the type of strings is List String -- A GADT data Expr a where EBool :: Bool -> Expr Bool EInt :: Int -> Expr Int EEqual :: Expr Int -> Expr Int -> Expr Bool eval :: Expr a -> a eval e = case e of EBool a -> a EInt a -> a EEqual a b -> expr1 = EEqual -- the type of expr1 is Expr Bool ret = eval expr1 -- ret is False
They are currently implemented in the GHC compiler as a non-standard extension, used by, among others, Pugs and Darcs. OCaml supports GADT natively since version 4.00. The GHC implementation provides support for existentially quantified type parameters and for local constraints.
History
An early version of generalized algebraic data types were described by and based on pattern matching in ALF. Generalized algebraic data types were introduced independently by and prior by as extensions to ML's and Haskell's algebraic data types. Both are essentially equivalent to each other. They are similar to the inductive families of data types found in Coq's Calculus of Inductive Constructions and other dependently typed languages, modulo the dependent types and except that the latter have an additional positivity restriction which is not enforced in GADTs. introduced extended algebraic data types which combine GADTs together with the existential data types and type class constraints introduced by, and. Type inference in the absence of any programmer supplied type annotations is undecidable and functions defined over GADTs do not admit principal types in general. Type reconstruction requires several design trade-offs and is an area of active research.
An important application of GADTs is to embed higher-order abstract syntax in a type safe fashion. Here is an embedding of the simply typed lambda calculus with an arbitrary collection of base types, tuples and a fixed point combinator: data Lam :: * -> * where Lift :: a -> Lam a -- ^ lifted value Pair :: Lam a -> Lam b -> Lam -- ^ product Lam :: -> Lam -- ^ lambda abstraction App :: Lam -> Lam a -> Lam b -- ^ function application Fix :: Lam -> Lam a -- ^ fixed point
And a type safe evaluation function: eval :: Lam t -> t eval = v eval = eval = \x -> eval eval = eval =
We would have run into problems using regular algebraic data types. Dropping the type parameter would have made the lifted base types existentially quantified, making it impossible to write the evaluator. With a type parameter we would still be restricted to a single base type. Furthermore, ill-formed expressions such as App would have been possible to construct, while they are type incorrect using the GADT. A well-formed analogue is App . This is because the type of x is Lam , inferred from the type of the Lam data constructor.