Record Syntax
If some fields need to be accessed often, it can be convenient to have helper functions for reading those fields. For instance, the type Person
might have multiple fields:
data Person = MkPerson String Int String String String deriving Show
A list of persons might look like the following:
people :: [Person]
people = [ MkPerson "Jane Doe" 21 "Houston" "Texas" "Engineer"
, MkPerson "Maija Meikäläinen" 35 "Rovaniemi" "Finland" "Engineer"
, MkPerson "Mauno Mutikainen" 27 "Turku" "Finland" "Mathematician"
]
Suppose that we need to find all engineers from Finland:
query :: [Person] -> [Person]
query [] = []
query ((MkPerson name age town state profession):xs)
| state == "Finland" && profession == "Engineer" =
(MkPerson name age town state profession) : query xs
| otherwise = query xs
Thus,
query people ==> [MkPerson "Maija Meikäläinen" 35 "Rovaniemi" "Finland" "Engineer"]
Note that the types of the fields give little information on what is the intended content in those fields. We need to remember in all places in the code that town
goes before state
and not vice versa.
Haskell has a feature called record syntax that is helpful in these kinds of cases. The datatype Person
can be defined as a record:
data Person = MkPerson { name :: String, age :: Int, town :: String, state :: String, profession :: String}
deriving Show
We can still define values of Person
normally, but the Show
instance prints the field names for us:
Prelude> MkPerson "Jane Doe" 21 "Houston" "Texas" "Engineer"
MkPerson {name = "Jane Doe", age = 21, town = "Houston", state = "Texas", profession = "Engineer"}
However, we can also define values using record syntax. Note how the fields don’t need to be in any specific order now that they have names.
Prelude> MkPerson {name = "Jane Doe", town = "Houston", profession = "Engineer", state = "Texas", age = 21}
MkPerson {name = "Jane Doe", age = 21, town = "Houston", state = "Texas", profession = "Engineer"}
Most importantly, We get accessor functions for the fields for free:
Prelude> :t profession
profession :: Person -> String
Prelude> profession (MkPerson "Jane Doe" 21 "Houston" "Texas" "Engineer")
"Engineer"
We can now rewrite the query function using these accessor functions:
query :: [Person] -> [Person]
query [] = []
query (x:xs)
| state x == "Finland" && profession x == "Engineer" =
x : query xs
| otherwise = query xs
You’ll probably agree that the code looks more pleasant now.
You can check your current points from the blue blob in the bottom-right corner of the page.