🎓 A1Learner
🔍
0 of 47 lessons completed

Haskell Type Family Examples

A type family is a type-level function that chooses a result type for each input type. The examples in this lesson show that idea in three different jobs.

A family picks the first component of a pair

First maps a pair type to its first component type. The first component of the pair is a number.

{-# LANGUAGE TypeFamilies #-}
type family First p where
  First (a, b) = a
firstOf :: (a, b) -> First (a, b)
firstOf (x, _) = x
main :: IO ()
main = print (firstOf (3, "hi"))

A family picks a function result type

Output maps Int to String and String to Int. A positive number gives a word, and a short string gives its length.

{-# LANGUAGE TypeFamilies #-}
type family Output a where
  Output Int = String
  Output String = Int
describe :: Int -> Output Int
describe n = if n > 0 then "positive" else "zero"
size :: String -> Output String
size s = length s
main :: IO ()
main = do
  putStrLn (describe 5)
  print (size "hi")

A family picks a transformation result type

Neg maps each input type to its own result type. Negating a number and negating a boolean give different kinds of results.

{-# LANGUAGE TypeFamilies #-}
type family Neg a where
  Neg Int = Int
  Neg Bool = Bool
negInt :: Int -> Neg Int
negInt x = -x
negBool :: Bool -> Neg Bool
negBool b = not b
main :: IO ()
main = do
  print (negInt 4)
  print (negBool True)

Example

{-# LANGUAGE TypeFamilies #-}
type family First p where
  First (a, b) = a
type family Output a where
  Output Int = String
  Output String = Int
type family Neg a where
  Neg Int = Int
  Neg Bool = Bool
firstOf :: (a, b) -> First (a, b)
firstOf (x, _) = x
describe :: Int -> Output Int
describe n = if n > 0 then "positive" else "zero"
negBool :: Bool -> Neg Bool
negBool b = not b
main :: IO ()
main = do
  print (firstOf (8, "bye"))
  putStrLn (describe 5)
  print (negBool True)

Key points

  • Type family: a type-level function that maps one type to another.
  • A type family can pick the first component of a pair type.
  • A type family can pick the result type of a function from its input type.
  • A type family can pick the result type of a transformation from its input type.
  • One family handles one job, so each job gets its own family.

In this example, three families each handle one job. First picks a pair component, Output picks a function result, and Neg picks a transformation result. The prints show the pair component, the word for a positive number, and the negation of true.

Note

Each family in this lesson is closed, so its equations are fixed in one place.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Haskell Playground

Exercise

Which job can a type family do?