Records

Contents
Declare a record
Accessors are functions
Record update
The duplicate name problem

Declare a record

Curly braces after the constructor give each field a name. The type is still an ordinary product type; the names are an addition, not a different kind of data:

data Person = Person { name :: String , age :: Int , active :: Bool } deriving (Show, Eq) ada = Person { name = "Ada", age = 36, active = True }

Construction by name is order independent, which matters as soon as two fields share a type. Person { age = 36, name = "Ada", active = True } is the same value.

Accessors are functions

Each field name becomes a function from the record to the field. That makes accessors usable wherever a function is expected:

name ada -- "Ada" map age [ada] -- [36] sortOn age people -- sort by a field

The last line is the idiom worth remembering. Sorting a list of records by one field needs no lambda, because the accessor already is the projection.

Record update

Copying a record with one field changed has its own syntax. The original is untouched, because nothing is mutable:

older = ada { age = age ada + 1 } name older -- "Ada", unchanged age older -- 37 -- several fields at once inactive = ada { active = False, age = 40 }

A record update copies the whole record, so it is cheap for a few fields and wasteful for a huge one updated in a tight loop. GHC optimises the common cases, but not all of them.

The duplicate name problem

Field names share one global namespace per module, so two records cannot both have a field called name without an extension. The practical workarounds are prefixes or separate modules:

-- both at once is a compile error data Person = Person { name :: String } data Company = Company { name :: String }

Prefix the fields (personName, companyName) or put each type in its own module and import it qualified. The DuplicateRecordFields extension lifts the restriction at the cost of vaguer error messages.

Next: newtype and type synonyms

Article author: Arthur Isaev

Related articles
Haskell
Haskell course: zero to hero in 50 lessons
What is Haskell and why it matters
Install the toolchain with GHCup
GHCi: the interactive shell
Your first program
Values with let and where
Types and type signatures
Functions and application
Currying and partial application
Operators, sections, and fixity
if, guards, and pattern guards
case expressions
Pattern matching
Tuples
Lists
Ranges and enumeration
List comprehensions
Recursion replaces loops
map, filter, and foldr
Lambdas and composition
Type classes
Parametric polymorphism
Maybe and null safety
Either and recoverable errors
data: product types
data: sum types
Records
newtype and type synonyms
Recursive data: binary trees
Functor
Applicative
Monad
do notation
IO and purity
Files and IO
Modules and imports
Cabal projects
Dependencies
Testing with HUnit
Property testing with QuickCheck
Laziness and infinite lists
Strictness and space leaks
Folds
Monoids
Traversable
Monad transformers
Errors and exceptions
Concurrency
Parsing with Megaparsec
Capstone: a todo CLI
Hero roadmap: the whole course on one page
Banner image

Search this site

Channel @aofeed Chat @aofeedchat

Contacts and cooperation:
I recommend our hosting beget.com
Write to info@aredel.com if you:
1. Want to write an article for our site or translate an article into your native language.
2. Want to place thematically relevant ads on the site.
3. Ads on my site pass maximum censorship. If you see an ad block unsuitable for school-age children, shocking or misleading - please contact us by e-mail
4. Found a mistake, inaccuracy, bug, etc. on the site. ... .......
5. Articles can be shared on social media by clicking a network icon: