Record Types
Haskell's data
command is versatile. We use it to define plain enums. We use it define data-bearing tagged unions. We use it to define really messy tuple types like this Friend
type:
-- name bday email phone address city state zip
data Friend = Friend String Date String String String String String String
Unlike the previous types we've defined in Haskell, Friend
has only a single variant. We still need to name the variant, even though there's only one. Here, both the type itself and the variant are named Friend
. That's legal.
Suppose we want a function to yield the name of a Friend
. The only way to extract the friend's name is through destructuring. So we write this accessor function:
name :: Friend -> String
name (Friend nombre _ _ _ _ _ _ _) = nombre
All but one of the fields is irrelevant, and they are therefore discarded with _
.
Then we starting adding accessors for the other fields:
birthday :: Friend -> Date
birthday (Friend _ date _ _ _ _ _ _) = date
email :: Friend -> String
email (Friend _ _ address _ _ _ _ _) = address
-- ...
But we give up, because this is too much work. Tuples of high arity are cumbersome. The Haskell designers agree, and that's why they also allow us to give the fields names through the language's record syntax. This revised definition ascribes names to the fields of Friend
:
data Friend = Friend { name :: String
, birthday :: Date
, email :: String
, phone :: String
, address :: String
, city :: String
, state :: String
, zipCode :: String } deriving Show
Placing the separating comma in front of a field rather than at the end of the preceding line is typical in Haskell programs.
Now that the fields are named, a Friend
is no longer a tuple but a record. The Haskell compiler automatically adds accessors for the fields of a record type. This interaction constructs a Friend
and then accesses its fields through these automatically defined functions:
> friend = Friend "Jasmine" (Date 2003 12 21) "eg@example.com" "?" "114 Whopper Lane" "Hogbottom" "AK" "41229"
> name friend
Jasmine
> email friend
eg@example.com
Record types are more humane than tuples in a couple of other ways. The constructors accept named parameters, and show
lists the data with names, as demonstrated in this GHCI interaction:
> friend = Friend { name = "Jasmine", birthday = Date 2003 12 21, email = "eg@example.com", phone = "?", address = "114 Whopper Lane", city = "Hogbottom", state = "AK", zipCode = "41229" }
> friend
Friend {name = "Jasmine", birthday = Date 2003 12 21, email = "eg@example.com", phone = "?", address = "114 Whopper Lane", city = "Hogbottom", state = "AK", zipCode = "41229"}