Do any functional programming languages have syntax sugar for changing part of an object?

Viewed 155

In imperative programming, there is concise syntax sugar for changing part of an object, e.g. assigning to a field:

foo.bar = new_value

Or to an element of an array, or in some languages an array-like list:

a[3] = new_value

In functional programming, the idiom is not to mutate part of an existing object, but to create a new object with most of the same values, but a different value for that field or element.

At the semantic level, this brings about significant improvements in ease of understanding and composing code, albeit not without trade-offs.

I am asking here about the trade-offs at the syntax level. In general, creating a new object with most of the same values, but a different value for one field or element, is a much more heavyweight operation in terms of how it looks in your code.

Is there any functional programming language that provides syntax sugar to make that operation look more concise? Obviously you can write a function to do it, but imperative languages provide syntax sugar to make it more concise than calling a procedure; do any functional languages provide syntax sugar to make it more concise than calling a function? I could swear that I have seen syntax sugar for at least the object.field case, in some functional language, though I forget which one it was.

(Performance is out of scope here. In this context, I am talking only about what the code looks like and does, not how fast it does it.)

2 Answers

Haskell records have this functionality. You can define a record to be:

data Person = Person
  { name :: String
  , age :: Int
  }

And an instance:

johnSmith :: Person
johnSmith = Person
  { name = "John Smith"
  , age = 24
  }

And create an alternation:

johnDoe :: Person
johnDoe = johnSmith {name = "John Doe"}
-- Result:
-- johnDoe = Person
--   { name = "John Doe"
--   , age = 24
--   }

This syntax, however, is cumbersome when you have to update deeply nested records. We've got a library lens that solves this problem quite well.


However, Haskell lists do not provide an update syntax because updating on lists will have an O(n) cost - they are singly-linked lists.

If you want efficient update on list-like collections, you can use Arrays in the array package, or Vectors in the vector package. They both have the infix operator (//) for updating:

alteredVector = someVector // [(1, "some value")]
-- similar to `someVector[1] = "some value"`

it is not built-in, but I think infix notation is convenient enough!

One language with that kind of sugar is F#. It allows you to write

let myRecord3 = { myRecord2 with Y = 100; Z = 2 }

Scala also has sugar for updating a Map:

ms + (k -> v)
ms updated (k,v)

In a language such as Haskell, you would need to write this yourself. If you can express the update as a key-value pair, you might define

let structure' =
  update structure key value

or

update structure (key, value)

which would let you use infix notation such as

structure `update` (key, value)
structure // (key, value)

As a proof of concept, here is one possible (inefficient) implementation, which also fails if your index is out of range:

module UpdateList (updateList, (//)) where
import Data.List (splitAt)

updateList :: [a] -> (Int,a) -> [a]
updateList xs (i,y) = let ( initial, (_:final) ) = splitAt i xs
  in initial ++ (y:final)

infixl 6 // -- Same precedence as +
(//) :: [a] -> (Int,a) -> [a]
(//) = updateList

With this definition, ["a","b","c","d"] // (2,"C") returns ["a","b","C","d"]. And [1,2] // (2,3) throws a runtime exception, but I leave that as an exercise for the reader.

H. Rhen gave an example of Haskell record syntax that I did not know about, so I’ve removed the last part of my answer. See theirs instead.

Related