0
votes

Okay, as someone who came from Object-Oriented programming not a week ago, Haskell is somewhat overwhelming - its likely that this has been answered, but all my research has been fruitless. Please bear with me.

Say that I have two algebraic data types:

data Person = Person {name :: String, houseNumber :: Integer, hasBorrowed :: Bool}
data Book   = Book   {borrower :: Person, title :: String}

Now, I know that you can simply extract a value from a single algebraic data type with a function:

getHouseNumber :: Person -> Integer
getHouseNumber (Person _ houseNumber _) = houseNumber

getBorrower :: Book -> Person
getBorrower (Book borrower _) = borrower

My question is (and I swear I'm going to smack myself in the head when I get the answer) how would I write a function which extracts houseNumber (as an example) straight from book? In other words:

getHouseNumberFromBook :: Book -> Integer

Thanks in advance.

2

2 Answers

3
votes

First, this is redundant

getHouseNumber :: Person -> Integer
getHouseNumber (Person _ houseNumber _) = houseNumber

since houseNumber is already defined automatically as a similar projection. We get this from using the record notation in the data declaration. That is, Haskell already automatically defines

houseNumber :: Person -> Integer
houseNumber (Person _ hN _) = hN

and there's no need to duplicate that. Similarly for borrower and other fields.

About the actual question, we can simply compose the accessors:

getHouseNumberFromBook :: Book -> Integer
getHouseNumberFromBook b = houseNumber (borrower b)

or, more idiomatically,

getHouseNumberFromBook :: Book -> Integer
getHouseNumberFromBook = houseNumber . borrower

This is so short that one can probably use its definition directly, without having to define a custom function.

1
votes

The fields of records are actually functions that extract a value from an ADT. So you have borrower :: Book -> Person and houseNumber :: Person -> Integer. Therefor you can use the composition operator . to create a new function houseNumber . borrower :: Book -> Integer.