When compiler version 0.10.6 is released, it will include a syntax for nested record updates.

Problem

Before this change, if we have a nested record structure such as:

r = { val: -1
    , level1: { val: -1
              , level2: { val: -1 }
              }
    }

To update .level1.val we’d have to write something like this:

r' = r { level1 = r.level1 { val = 1 } }

This is fairly annoying to write: we need to mention both r and level1 twice. With even more nesting it just gets worse:

r'' = r { level1 = r.level1 { level2 = r.level1.level2 { val = 2 } } }

Solution

With the new syntax, the following equivalent expressions are supported:

r' = r { level1 { val = 1 } }
r'' = r { level1 { level2 { val = 2 } } }

To update all the val fields it’d look like this:

r' = r { val = 0
       , level1 { val = 1
                , level2 { val = 2 }
                }
       }

Evaluation

In the previous example we updated an object computed by the expression r - which is just a variable. However if we compute a record by some more complicated expression and then try to update, we wouldn’t just blindly substitute the expression in:

-- `f r` has been repeated
s = (f r) { level1 = (f r).level1 { val = 1 } }

Instead we would first compute f r and refer to the result twice:

s' = let fr = f r in fr { level1 = fr.level1 { val = 1 } }

When the compiler desugars nested record updates, to prevent reevaluating the object expression, it introduces a let binding like the previous example.