Home / Haskell
Haskell
Haskell at the expert level: GADTs, type families, DataKinds, lenses, STM concurrency, MTL, free monads, generics and performance. All examples verified with the real compiler.
Haskell Advanced is where the type system stops describing your program and starts enforcing its rules. GADTs tie a value to the exact type it carries, type families compute new types from old ones, DataKinds lifts values into types, and lenses reach inside nested records without boilerplate. Forty-seven lessons, all verified against GHC output, take you from a typed expression evaluator to a concurrent task processor.
Course contents
Work top to bottom — the sidebar is the course. Topics later in the list assume the ones before them.
Haskell Advanced Introduction
Advanced · ⏱ 3 min · standalone lesson
GADTs
- Haskell GADT Idea
- Haskell GADT Typed Expressions
- Haskell GADT Pattern Matching
- Haskell GADT Existentials
- Haskell GADTs Versus ADTs
Type Families
- Haskell Type Family Idea
- Haskell Associated Types
- Haskell Closed Type Families
- Haskell Type Family Examples
- Haskell Functional Dependencies
DataKinds and Type-Level Programming
- Haskell DataKinds Idea
- Haskell Promoted Types
- Haskell Type-Level Naturals
- Haskell Type-Level Lists
- Haskell Singleton Pattern
Lenses
- Haskell Lens Idea
- Haskell Lens Getter and Setter
- Haskell Lens Composition
- Haskell Van Laarhoven Lens
- Haskell Lens Traversals
Concurrency and STM
- Haskell STM Idea
- Haskell TVar Basics
- Haskell STM Transactions
- Haskell STM Retry
- Haskell STM Composition
- Haskell Chan and MVar
MTL in Depth
- Haskell MTL Idea
- Haskell MonadReader Class
- Haskell MonadState Class
- Haskell MonadError Class
- Haskell MTL Stack
Free Monads
- Haskell Free Monad Idea
- Haskell Free Monad Interpreters
- Haskell Free Monads Versus MTL
- Haskell Free Monad Patterns
GHC.Generics
- Haskell GHC Generics Idea
- Haskell Generic Deriving
- Haskell Generic Representation
- Haskell Generics Patterns
Performance in Depth
- Haskell Fusion Idea
- Haskell Strictness Analysis
- Haskell Profiling Concepts
- Haskell Memory Patterns
- Haskell Optimization Notes
Haskell Project Concurrent Processor
Advanced · ⏱ 5 min · standalone lesson
Haskell Project Small Interpreter
Advanced · ⏱ 5 min · standalone lesson
Haskell at the advanced level
Intermediate Haskell gave you the vocabulary for building programs: functors, applicatives, monads, transformers, laziness, and strictness. Advanced Haskell turns that vocabulary into leverage. The central idea is simple to state and deep in consequence: when a type says more, the compiler catches more. A length-indexed vector cannot be read empty, because the empty case has a different type from the non-empty case. A typed expression evaluator cannot return a boolean where a number belongs, because each constructor declares its own result type.
The course moves in four arcs. The first arc is types that compute: GADTs, open and closed type families, associated types, functional dependencies at first sight, and DataKinds with type-level naturals, type-level lists, and the singleton pattern. The second arc is access and change: lenses built by hand, from getter and setter pairs through composition to the van Laarhoven form and traversals that touch many targets at once. The third arc is effects at scale: software transactional memory, MTL typeclasses, free monads written by hand, and GHC generics. The fourth arc is performance in depth: fusion, strictness analysis, profiling concepts, memory patterns, and optimization notes, all argued from counted work rather than timings.
Forty-seven lessons in ten groups, plus two closing projects, make up the course. Lesson times total 164 minutes. The concurrent processor project runs fixed jobs through TVars, MVars, and channels with every print done by the main thread, so its output is deterministic. The small interpreter project evaluates expressions with variables, where an unknown name yields Nothing instead of a crash.
What you will learn
Work through the groups in sequence to gain:
- Write GADTs whose constructors each declare their own result type, and evaluate typed expressions safely
- Pattern match on a GADT so the type checker refines the result type in each branch
- Hide a value behind an existential wrapper and keep only the constraint that survives
- Compute new types with open type families, and fix a family inside a class as an associated type
- Order closed family equations so the first match wins and later equations act as fallbacks
- State a functional dependency so the collection type determines the element type
- Promote data constructors into types with DataKinds and read kind annotations with confidence
- Index a vector by its length at the type level so an empty vector can never be read
- Build type-level lists and mirror a type-level length with a singleton value
- Bundle a getter and a setter into a lens, compose lenses outer first, and traverse many targets
- Read the van Laarhoven lens type and explain why viewing uses Const and setting uses Identity
- Share state between threads with TVars, compose transactions, and retry until a value changes
- Use MVars and channels as rendezvous points so concurrent output stays deterministic
- Read MTL code through its classes: MonadReader, MonadState, and MonadError, plus a full stack
- Write a free monad by hand and interpret the same program twice, once for IO and once for testing
- Derive Generic, round-trip a value through its representation, and count fields generically
- Argue performance from counted work: fusion results, strictness choices, and memory shapes
- Finish a concurrent processor that runs jobs through shared state and prints a fixed summary
- Finish a small interpreter that evaluates expressions with variables and reports unknown names
Who this Haskell course is for
This course assumes the intermediate course, or the equivalent: functors, applicatives, monads, transformers, laziness, strictness, deeper typeclasses, deeper IO, and error handling. If a monad transformer stack still feels unfamiliar, pause here and complete the intermediate course first; the MTL group here moves quickly and presumes that stack fluency.
Programmers who have shipped Haskell in production often arrive here with a specific pain: an ordinary algebraic data type that lets invalid states through, a record nested three levels deep that resists updating, or a concurrent program whose locks deadlock on a bad day. Each group in this course answers one such pain with a mechanism rather than a workaround.
Expect two hours and forty-four minutes of lesson time in total. The type-level groups reward slow reading: a GADT lesson that clicks on the second pass is normal, and the exercises are built to catch the exact misunderstanding that blocks the next lesson.
How this course works
Order is the pedagogy. GADTs come before type families because a family that computes over a GADT result type is the first payoff for typed expressions. DataKinds comes after families because a promoted constructor is only useful once you can compute with it. Lenses come after the type-level groups because a lens type is itself a small exercise in higher-rank types. STM comes after lenses because shared state is where pure reasoning meets real threads.
GHC 9.10.3 compiled each example and ran it twice, and the printed output in every lesson is the exact output of those runs. That guarantee matters most exactly here: a GADT program that typechecks but evaluates wrong, or an STM program whose output depends on scheduling, would teach the wrong lesson. Concurrent examples print only from the main thread, so their outputs are stable across runs.
Every lesson closes with an exercise whose answer explains its reasoning in full. Several exercises ask you to judge whether a program typechecks before you scroll on, the quickest check of whether a type-level idea has really landed.
Your progress lives in your own browser, so a half-finished group waits for you with no account needed. Every lesson, project, and explained exercise answer is free.
Frequently asked questions
Do I need Haskell Intermediate before this course?
In practice, yes. This course assumes functors, applicatives, monads, transformers, laziness, strictness, deeper typeclasses, deeper IO, and error handling. The intermediate course teaches exactly that material, and this course starts building on it from lesson one.
What is a GADT, in plain terms?
A GADT is a data type whose constructors each choose their own result type. An ordinary type has one result type for all its constructors; a GADT lets a Lit constructor return an integer expression while an IsZero constructor returns a boolean expression. The evaluator then cannot mix the two up, because the types keep them apart.
How do type families differ from generics?
A type family is a function computed by the type checker: give it a type, and it answers with another type. Generics instead expose the shape of a type so one function can work for many types. Families answer questions about types; generics write code that adapts to types.
Do I need the lens library to use lenses?
No. This course builds lenses by hand from getter and setter pairs, then shows the van Laarhoven form with a small Const type written in the lesson. The library is convenient in real projects, but the idea is fully visible without it.
Why STM instead of locks?
Because transactions compose and locks do not. Two STM transactions joined in one block are still one transaction, so either all of their effects land or none do. A retry waits until a value it read changes, which removes the usual deadlock shape where two threads each hold one lock and want the other.
How long does the Haskell advanced course take?
Lesson times total 164 minutes. The GADT and type-level groups deserve a repeat visit, so budget time for a second pass through them.
What can I build after this course?
Concurrent services with transactional state, interpreters and small languages with typed expressions, and libraries whose types rule out whole classes of misuse. The processor and interpreter projects show both patterns end to end.
Next steps
- Haskell Intermediate ❯ — The level before this one: functors, applicatives, monads, transformers, laziness, deeper typeclasses, deeper IO, and error handling — the ground this course stands on.
- Scala Advanced ❯ — A parallel advanced step in a second typed functional language: higher-kinded types, given instances, type classes, and effect systems, for readers who want the same ideas in Scala.