Shorthand way for assigning a single field in a record, while copying the rest of the fields?

Let's say I have the following record ADT:

data Foo = Bar { a :: Integer, b :: String, c :: String }

I want a function that takes a record and returns a record (of the same type) where all but one of the fields have identical values to the one passed as argument, like so:

walkDuck x = Bar { a = a x, b = b x, c = lemonadeStand (a x) (b x) }

The above works, but for a record with more fields (say 10), creating a such function would entail a lot of typing that I feel is quite unnecessary.

Are there any less tedious ways of doing the same?


Yes, there's a nice way of updating record fields. In GHCi you can do --

> data Foo = Foo { a :: Int, b :: Int, c :: String }  -- define a Foo
> let foo = Foo { a = 1, b = 2, c = "Hello" }         -- create a Foo
> let updateFoo x = x { c = "Goodbye" }               -- function to update Foos
> updateFoo foo                                       -- update the Foo
Foo {a = 1, b = 2, c = "Goodbye" }

This is a good job for lenses:

data Foo = Foo { a :: Int, b :: Int , c :: String }

test = Foo 1 2 "Hello"

Then:

setL c "Goodbye" test

would update field 'c' of 'test' to your string.


You don’t need to define auxiliary functions or employ lenses. Standard Haskell has already what you need. Let’s take the example by Don Stewart:

data Foo = Foo { a :: Int, b :: Int , c :: String }

test = Foo 1 2 "Hello"

Then you can just say test { c = "Goodbye" } to get an updated record.