NOW LET US – AI RAG SaaS Studio TP.HCM
NOW LET US
Digital Product Studio
Back to news
DEV-TOOLS...2 min read

Prefer do notation over Applicative operators when assembling records (2024)

Share
NOW LET US Article – Prefer do notation over Applicative operators when assembling records (2024)

This post explains why using `do` notation with `RecordWildCards` is superior to `Applicative` operators for record assembly, focusing on ergonomics, order independence, and error clarity.

This is a short post explaining why you should prefer do notation when assembling a record, instead of using Applicative operators (i.e. (<$>) / (<*>)). This advice applies both for type constructors that implement Monad (e.g. IO) and also for type constructors that implement Applicative but not Monad (e.g. the Parser type constructor from the optparse-applicative package). The only difference is that in the latter case you would need to enable the ApplicativeDo language extension.

The guidance is pretty simple. Instead of doing this:

data Person = Person
{ firstName :: String
, lastName :: String
}
getPerson :: IO Person
getPerson = Person <$> getLine <*> getLine

... you should do this:

{-# LANGUAGE RecordWildCards #-}
{-# OPTIONS_GHC -Werror=missing-fields #-}
data Person = Person
{ firstName :: String
, lastName :: String
}
getPerson :: IO Person
getPerson = do
firstName <- getLine
lastName <- getLine
return Person{..}

Why is the latter version better? There are a few reasons.

Ergonomics

It's more ergonomic to assemble a record using do notation because you're less pressured to try to cram all the logic into a single expression. For example, suppose we wanted to explicitly prompt the user to enter their first and last name. The typical way people would extend the former example using Applicative operators would be something like this:

getPerson :: IO Person
getPerson =
Person
<$> (putStrLn "Enter your first name:" *> getLine)
<*> (putStrLn "Enter your last name:" *> getLine)

The expression gets so large that you end up having to split it over multiple lines, but if we're already splitting it over multiple lines then why not use do notation?

getPerson :: IO Person
getPerson = do
putStrLn "Enter your first name:"
firstName <- getLine
putStrLn "Enter your last name:"
lastName <- getLine
return Person{..}

Much clearer! Also, the version using do notation doesn't require that the reader is familiar with all of the Applicative operators, so it's more approachable to Haskell beginners.

Order insensitivity

Suppose we take that last example and then change the Person type to reorder the two fields:

data Person = Person
{ lastName :: String
, firstName :: String
}

... then the former version using Applicative operators would silently break: the first name and last name would now be read in the wrong order. The latter version (using do notation) is unaffected. More generally, the approach using do notation never breaks or changes its behavior if you reorder the fields in the datatype definition. It's completely order-insensitive.

Better error messages

If you add a new argument to the Person constructor, like this:

data Person = Person
{ alive :: Bool
, firstName :: String
, lastName :: String
}

... and you don't make any other changes to the code then the former version will produce cryptic error messages about type mismatches. Whereas the latter version produces a much more direct error message indicating which fields of 'Person' are not initialized. This error message more clearly suggests to the developer what needs to be fixed: the alive field needs to be initialized.

Caveats

This advice obviously only applies for datatypes that are defined using record syntax. The approach I'm advocating here doesn't work at all for datatypes with positional arguments. However, this advice does still apply for type constructors that are Applicatives and not Monads; you just need to enable the ApplicativeDo language extension.

© 2026 Now Let Us. All rights reserved.

Source: Hacker News

Advertisement
Ad slot ready: 5887729102

More in this category

NOW LET US Related – GLM 5.2 Is Out

dev-tools

GLM 5.2 Is Out

Zhipu AI has officially released GLM-5.2, its most powerful open-source model to date, featuring a 1M context window and advanced long-horizon task capabilities. The release underscores Zhipu's commitment to open-source AI and global scientific collaboration amid rising technological restrictions.

NOW LET US Related – Noise infusion banned from statistical products published by Census Bureau

dev-tools

Noise infusion banned from statistical products published by Census Bureau

The U.S. Department of Commerce has banned "noise infusion" from statistical products published by the Census Bureau, a decision that could have severe consequences for both data utility and privacy protection.

NOW LET US Related – Treating pancreatic tumours may have revealed cancer's master switch

dev-tools

Treating pancreatic tumours may have revealed cancer's master switch

A promising new drug called daraxonrasib has shown breakthrough results in treating pancreatic cancer, doubling median survival times. This achievement could pave the way for an entirely new class of cancer treatments.

NOW LET US Related – Every Frame Perfect

dev-tools

Every Frame Perfect

In UI design, perfection isn't just about the start and end states, but every single transition frame in between. Polishing these micro-interactions is key to building user trust.

NOW LET US Related – Leaving Mozilla

dev-tools

Leaving Mozilla

A poignant and candid reflection from a 15-year Mozilla veteran upon their departure. The author highlights the leadership's missteps in trying to emulate tech giants and urges Mozilla to return to its core values: community and uniqueness.

NOW LET US Related – Shepherd's Dog: A Game by the Most Dangerous AI Model

dev-tools

Shepherd's Dog: A Game by the Most Dangerous AI Model

A developer tested Anthropic's latest, supposedly 'too dangerous' AI model by asking it to build a long-held game idea in a single shot. The model succeeded, generating a complete 2,319-line game after a 45-minute reasoning session.

EXPLORE TOPICS

Discover All Categories

Deep dive into the specific technology sectors that matter most to you.