Haskell Type Families Guide — Type-Level Functions and Associated Types
In this tutorial, you will learn about Haskell Type Families Guide. We cover key concepts, practical examples, and best practices to help you master this topic.
Haskell type families are type-level functions that map types to types -- open families for extensible mappings (TypeFamily), closed families for exhaustive pattern matching, and associated types within typeclasses for type-indexed data families.
Open Type Families
{-# LANGUAGE TypeFamilies #-}
-- Open type family (extensible)
type family Elem container :: *
-- Instances
type instance Elem [a] = a
type instance Elem (Maybe a) = a
type instance Elem (Map k v) = v
-- Usage
first :: container -> Elem container -> Bool
-- first xs x = ... checks if x is first element
Closed Type Families
{-# LANGUAGE TypeFamilies #-}
-- Closed family (exhaustive matching)
type family TypeSize a where
TypeSize Int = 4
TypeSize Double = 8
TypeSize Bool = 1
TypeSize a = 0 -- default case
-- Type-level computation
type family Add a b where
Add Zero b = b
Add (Succ a) b = Succ (Add a b)
Associated Type Families
{-# LANGUAGE TypeFamilies #-}
class Collection c where
type Item c -- associated type
insert :: Item c -> c -> c
member :: Item c -> c -> Bool
instance Collection [a] where
type Item [a] = a
insert x xs = x : xs
member x xs = elem x xs
instance Collection (Set a) where
type Item (Set a) = a
insert x s = Set.insert x s
member x s = Set.member x s
Data Families
{-# LANGUAGE TypeFamilies #-}
-- Data family: different data structure per type
data family Array a
data instance Array Int = IArray (Vector Int)
data instance Array Double = DArray (Vector Double)
data instance Array Bool = BArray (Vector Bool)
-- Usage
createArray :: Array a -> Int -> IO ()
-- dispatches to correct implementation
Common Mistakes
1. Overlapping instances
Open type family instances must not overlap. Closed families can overlap with order-based resolution.
2. Instance resolution order
Closed families try instances top-to-bottom. Put more specific patterns first.
3. Type family vs functional dependency
Both associate types with other types. Type families are more expressive. Functional dependencies are simpler.
Practice Questions
1. What is the difference between open and closed type families? Open families allow new instances anywhere. Closed families define all instances in one block.
2. What do associated type families enable? Type-indexed type mappings within typeclasses. Each instance defines its own auxiliary type.
3. What is a data family? Similar to a type family but defines type constructors (data types) rather than type aliases.
FAQ
{{< faq question="Can type families be recursive?" >}}
Yes. Closed type families support Recursion: type family Fact n where { Fact 0 = 1; Fact n = n * Fact (n-1) }.
{{< /faq >}}
{{< faq question="What is injectivity?" >}}
A type family can be declared injective: type family F a = r | r -> a. This enables better type inference.
{{< /faq >}}
{{< faq question="Are type families computed at compile time?" >}} Yes. Type families are fully evaluated during Type Checking. There is no runtime cost. {{< /faq >}}
What's Next
Now learn about Template Haskell.
| Topic | Description | Link |
|---|---|---|
| Template Haskell | Meta-programming | {{< ref "30-template-haskell" >}} |
| Julia | Start learning Julia | Julia |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro