RecordDotSyntax in Haskell
Riccardo Odone
Posted on June 2, 2020
You can keep reading here or jump to my blog to get the full experience, including the wonderful pink, blue and white palette.
I started studying hardcore functional programming by fiddling with PureScript. Back then, using records felt natural since they are first-class citizens in the language:
-- PureScript
type Person = { name :: String, age :: Int }
type Company = { name :: String, owner :: Person }
display :: Company -> String
display c = c.name <> " is run by " <> c.owner.name
nameAfterOwner :: Company -> Company
nameAfterOwner c = c{name = c.owner.name <> "'s Company"}
When I switched to Haskell it took me ages to get used to the quirks of its record syntax:
-- Haskell
data Person = Person { personName :: String, personAge :: Int }
-- ^ Define a new type.
-- ^ Add constructor.
-- ^ Prefix.
-- ^ Prefix.
-- Haskell automatically created
-- Person :: String -> Int -> Person
-- personName :: Person -> String
-- personAge :: Person -> Int
data Company = Company { companyName :: String, companyOwner :: Person }
-- Field names are prefixed, otherwise the program would not
-- compile because of the overlapping `name` getters.
display :: Company -> String
display c = companyName c <> " is run by " <> personName (companyOwner c)
nameAfterOwner :: Company -> Company
nameAfterOwner c = c {companyName = personName (companyOwner c) <> "'s Company"}
Of course some type system or category theory trickery would solve that but it just does not feel right for this specific use-case.
Luckily, the RecordDotSyntax proposal has been accepted. We just need to hang tight while it gets implemented. But if you are like me and cannot wait to start using it, a preprocessor is available today!
In other words, using record-dot-preprocessor, the following code is valid Haskell:
-- Haskell
data Company = Company {name :: String, owner :: Person}
data Person = Person {name :: String, age :: Int}
display :: Company -> String
display c = c.name ++ " is run by " ++ c.owner.name
nameAfterOwner :: Company -> Company
nameAfterOwner c = c{name = c.owner.name ++ "'s Company"}
PureScript has a ton of other niceties. "Differences from Haskell" is a great read on that account.
What's your experience with records in Haskell? Hyped up about RecordDotSyntax? Let's talk on Twitter!
Get the latest content via email from me personally. Reply with your thoughts. Let's learn from each other. Subscribe to my PinkLetter!
Posted on June 2, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.