loading...

RecordDotSyntax in Haskell

riccardoodone profile image Riccardo Odone Updated on ・2 min read

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 by:

riccardoodone profile

Riccardo Odone

@riccardoodone

🏳️‍🌈 Pronoun.is/he 💣 Maverick & Leader @Lunar_Logic 🧑‍💻 Functional Programming Rambler 🔥 Sometimes failing 🚀 Sometimes succeeding 💡Always learning

Discussion

markdown guide