Skip to content

0023 ‐ Email Tutorials Haskell For Beginners ‐ Algebraic Data Types with Haskell

Bernard Sibanda edited this page Dec 16, 2025 · 2 revisions

Same video: Algebraic Data Types with Haskell

23.1 A Beginner Gotcha: “No instance for Show …”

Earlier we defined:

newtype Day   = Day   Int
newtype Month = Month Int
newtype Year  = Year  Int

Now imagine you load this into ghci and try:

ghci> d1

You might see an error like:

No instance for (Show Day) …

What does this mean?

  • ghci is trying to print the value.
  • To print a value, Haskell uses the Show type class.
  • Our Day, Month, and Year types don’t yet have a Show instance.
  • So ghci says: “I don’t know how to show (print) a Day.”

We don’t fully understand type classes yet, so the course asks you to:

newtype Day   = Day   Int   deriving Show
newtype Month = Month Int   deriving Show
newtype Year  = Year  Int   deriving Show

Now:

  • The deriving Show clause tells the compiler:

    “Please auto-generate the code needed to convert this type to a String.”

  • After reloading in ghci, printing d1, d2, etc. works.

You can think of deriving Show (for now) as:

“Make this type printable in ghci and error messages.”

We’ll properly understand Show and type classes in a later module.

23.2 Defining a Custom Product Type with data

Now we build our own product type for dates using data.

Example:

data DateTC
  = DateDC Int Int Int
  deriving Show

Breakdown:

  • data – we are defining a new type.

  • DateTC – the type constructor (the name of our type).

  • = – definition.

  • DateDC Int Int Int – a data constructor (or value constructor) that:

    • Takes three Ints (day, month, year).
    • Constructs a value of type DateTC.
  • deriving Show – auto-generate Show so we can print it in ghci.

We can read it as:

“We define a custom type DateTC with one constructor DateDC that stores three Ints.”

23.3 Type Constructor vs Data Constructor

Using the “TC” and “DC” suffixes is just to make the teaching clearer:

data DateTC = DateDC Int Int Int
              deriving Show
  • Type constructor: DateTC

    • Used in type signatures.
  • Data constructor: DateDC

    • Used to build actual values.

Example values:

d2 :: DateTC
d2 = DateDC 1 1 2025

d3 :: DateTC
d3 = DateDC 31 12 1999
  • In the type signature, we use DateTC.
  • In the value definition, we call DateDC like a function.

23.4 Constructors Act Like Functions

Ask ghci for the type of the data constructor:

ghci> :t DateDC
DateDC :: Int -> Int -> Int -> DateTC

So DateDC:

  • Takes 3 Int arguments.
  • Returns a DateTC.

This means data constructors behave like functions:

DateDC 1 1 2025   -- applying a “function” of 3 Ints

Now, what about this more idiomatic declaration?

data Date = Date Int Int Int
  deriving Show

Then:

  • Date (in a type signature) refers to the type.
  • Date (in a value) refers to the data constructor / function.

Example:

today :: Date
today = Date 1 1 2025

ghci:

ghci> :t Date
Date :: Int -> Int -> Int -> Date
  • The first Date (that we ask :t about) is the data constructor.
  • The second Date (in the type) is the type constructor.
  • After :: only types appear, so that Date must be the type.

If you ask for the type of the type constructor directly (in a polymorphic sense), you’ll get an error here, because :t is for values/functions, not for “types of types”. We’ll revisit this when we talk about polymorphic types and kinds.

23.5 Why Custom Product Types Help (but Don’t Fix Everything Yet)

Compare:

-- Raw triple of Ints
date1 :: (Int, Int, Int)

-- Custom type
date2 :: Date

With our custom type:

  • The type signatures clearly state “this is a Date”.
  • It’s easier to understand and maintain.

But we’re still using raw Ints inside:

badDate :: Date
badDate = Date 31 31 2025  -- invalid month, but type-checks

So:

  • We gained readability, but not full validity guarantees yet.
  • Later, we’ll refine the internal types (Day, Month, Year with newtype or smart constructors) to prevent invalid dates.

23.6 Quick Intro to Sum Types: The Bool Example

We’ve seen product types (combinations of values). Now we look at sum types (choices between alternatives).

The Bool type is defined like this:

data Bool = True | False
  • data – we’re defining a type.
  • Bool – the type constructor / type name.
  • = – definition.
  • True | Falsetwo data constructors, separated by | (read as “or”).

Read aloud:

Bool is a type that can be True or False.”

Key points:

  • The | (pipe) in a data declaration means “or” between constructors.

  • Bool is a sum type:

    • It has 2 constructors.
    • So it has exactly 2 possible values.
  • In general:

    • Sum type: number of values = sum of values of each alternative.
    • Product type: number of values = product of values of each component.

We’ll see more complex sum types (with constructors that take arguments) later, but Bool is the simplest possible example.

23.7 Glossary

  • Product type: A type that combines several components (like tuples or our Date), where the number of possible values is the product of the possibilities of each component.
  • Sum type: A type that represents a choice between alternatives (like Bool), where the number of possible values is the sum of the alternatives’ possibilities.
  • Type constructor: The name of the type itself (e.g. Date, Bool), used in type signatures.
  • Data constructor / Value constructor: The “function” that builds values of the type (e.g. Date 1 1 2025, True, False).
  • deriving Show: An instruction to the compiler to auto-generate printing code so values can be converted to String (used by ghci and error messages).

23.8 Multiple Choice Questions (with Answers)

Q1. What does deriving Show on a type declaration do (in beginner-friendly terms)?

A. It automatically validates that the data is always correct. B. It tells the compiler how to convert values of the type to String, so they can be printed. C. It makes the type faster at runtime. D. It turns the type into a sum type.

Answer: B

Q2. In the declaration data Date = Date Int Int Int, what is Date?

A. Only a type constructor. B. Only a data constructor. C. Both a type constructor and a data constructor, depending on context. D. Neither – Date is just a synonym.

Answer: C

Q3. What is the type of the data constructor Date in data Date = Date Int Int Int?

A. Date B. Int -> Date C. Int -> Int -> Int -> Date D. (Int, Int, Int) -> Date

Answer: C

Q4. Why is Bool considered a sum type?

A. Because it stores the sum of two Ints. B. Because its values are formed from the Cartesian product of two sets. C. Because it has two alternatives (True and False), and the total number of values is the sum of the alternatives. D. Because it uses addition operators internally.

Answer: C

Q5. What does the | symbol mean in a Haskell data declaration like data Bool = True | False?

A. It separates arguments to a constructor. B. It means “and”, both constructors must hold at once. C. It means “or”: the type can be constructed by any one of the alternatives. D. It means division.

Answer: C

Quizz & Progress Badge NFT

Clone this wiki locally