R. Rengold
R. Rengold

Reputation: 193

Haskell - Implementing function which extracts values from an algebraic data type

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.

Upvotes: 0

Views: 120

Answers (2)

Will Sewell
Will Sewell

Reputation: 2643

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.

Upvotes: 1

chi
chi

Reputation: 116164

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.

Upvotes: 3

Related Questions