The more expressive the types are, the more safety we can ensure at compile-time. What's more, expressive types serve as documentation that is always up-to-date.
A type that has type variables on the left-hand side that do not appear on the right-hand-side at all is called a phantom type. Such type variables are a cheap, in fact free, technique to guarantee correctness in multiple situations. An example from base is Data.Fixed
, in which the precision of fixed-precision arithmetic is encoded in a phantom type.
An extremely useful class of phantom types is obtained in conjunction with Generalized Algebraic Data Types (GADT). As a little silly example, consider:
-- file: gadts.hs {-# LANGUAGE GADTs #-}data Value a where Boolean :: Bool -> Value Bool Not :: Value Bool -> Value Bool Numeric :: Num a => a -> Value a Sum :: Num a => Value a -> Value a -> Value a
The first two constructors allow us to build values that contain...