Road to Haskeller #9 - Records

Last Edited: 6/21/2024

The blog post introduces how to define datatypes with record syntax in Haskell.

Haskell & Records

Inconvinience with Datatypes

In the previous article, we learned how we can define a new datatype. Suppose you are building a web application in Haskell, and you want to define a new datatype User for keeping track of user's information such as first name, last name, age, email, and phone number. The definition of User would look like the following.

data User = User String String Int String String

This is already confusing as to what points to what information about the user, but let's continue with this set up. Suppose you have to access to the user's information in various parts of application. With the above definition, you would have to build the following helper functions.

firstName :: User -> String
firstName (User firstname _ _ _ _) = firstname
 
lastName :: User -> String
lastName (User _ lastname _ _ _) = lastname
 
age :: User -> Int
age (User _ _ age _ _) = age
 
email :: User -> String
email = (User _ _ _ email _) = email
 
phoneNumber :: User -> String
phoneNumber (User _ _ _ _ phonenumber) = phonenumber
 
--- Example
user = User "Micheal" "Jordan" 25 "mjordan@gmail.com" "123-456-789"
firstName user --- "Micheal"
age user --- 25

Wow, this is a lot of work just for retrieving values in a user. Do we have to do this for every datatype? Luckly, Haskell already got us covered.

Records

Haskell prepared us a record syntax for the situations like the above. Let's use record to re-define User.

data User = User {
  firstName :: String,
  lastName :: String,
  age :: Int,
  email :: String,
  phoneNumber :: String
}

When we define User like the above, Haskell automatically generate funtions to retrieve values so that we don't have to manually define them.

--- Without defining functions
user = User "Micheal" "Jordan" 25 "mjordan@gmail.com" "123-456-789"
firstName user --- "Micheal"
age user --- 25

We can use record synax for value constructors with multiple arguments as well.

data Point = 
  D2 {x::Int, y::Int}
  | D3 {x::Int, y::Int, z::Int}
 
x (D2 1 2) --- 1
x (D3 1 2 3) --- 1
z (D2 1 2) --- Err Undefined
z (D3 1 2 3) --- 3

Exercises

This is an exercise section where you can test your understanding of the material introduced in the article. I highly recommend solving these questions by yourself after reading the main part of the article. You can click on each question to see its answer.

Resources