Haskell Type Family Idea
A type family is a function at the type level. It takes a type as input and gives a type as output.
A list family gives its element type
Elem maps a list type to the type of its elements. The first element of a list of numbers is a number.
{-# LANGUAGE TypeFamilies #-}
type family Elem c
type instance Elem [a] = a
firstElem :: [a] -> Elem [a]
firstElem (x : _) = x
main :: IO ()
main = print (firstElem [7, 8])A Maybe family gives its wrapped type
Elem maps a Maybe type to the type wrapped inside it. The value inside Just 9 is a number.
{-# LANGUAGE TypeFamilies #-}
type family Elem c
type instance Elem (Maybe a) = a
unwrap :: Maybe a -> Elem (Maybe a)
unwrap (Just x) = x
main :: IO ()
main = print (unwrap (Just 9))An open family gains a case for a new type
A new collection type can add its own Elem case. The case for Box gives the type inside the box.
{-# LANGUAGE TypeFamilies #-}
data Box a = Box a
type family Elem c
type instance Elem (Box a) = a
unbox :: Box a -> Elem (Box a)
unbox (Box x) = x
main :: IO ()
main = print (unbox (Box 5))Example
{-# LANGUAGE TypeFamilies #-}
type family Elem c
type instance Elem [a] = a
type instance Elem (Maybe a) = a
type instance Elem (Box a) = a
data Box a = Box a
firstElem :: [a] -> Elem [a]
firstElem (x : _) = x
unwrap :: Maybe a -> Elem (Maybe a)
unwrap (Just x) = x
unbox :: Box a -> Elem (Box a)
unbox (Box x) = x
main :: IO ()
main = do
print (firstElem [7, 8])
print (unwrap (Just 9))
print (unbox (Box 5))Key points
- Type family: a type-level function that maps one type to another.
- A type family computes a type, just as an ordinary function computes a value.
- Use an open type family to add new cases later for new types.
- Type instance: the equation that fixes one input type to one output type.
- The compiler replaces a family application with its result type during type checking.
In this example, Elem is declared once and given three cases, one for lists, one for Maybe, and one for Box. Each helper returns the element type its case promises. The three prints show the first list element, the wrapped value, and the boxed value.
Note
An open family needs the TypeFamilies language extension.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Haskell Playground
Exercise
What does Elem [Int] stand for after the instance Elem [a] = a?