6.5.10. Overloaded record update — Glasgow Haskell Compiler 9.2.0.20210331 User's Guide

# 6.5.10. Overloaded record update

`OverloadedRecordUpdate`

  Since: | 9.2.0

  Provides record ‘.’ syntax in record updates e.g. `x{foo.bar = 1}`.

EXPERIMENTAL This design of this extension may well change in the future. It would be inadvisable to start using this extension for long-lived libraries just yet.

It’s usual (but not required) that this extension be used in conjunction with Overloaded record dot.

Example:

    {-# LANGUAGE AllowAmbiguousTypes, FunctionalDependencies, ScopedTypeVariables, PolyKinds, TypeApplications, DataKinds, FlexibleInstances #-}
    {-# LANGUAGE NamedFieldPuns, RecordWildCards #-}
    {-# LANGUAGE OverloadedRecordDot, OverloadedRecordUpdate, RebindableSyntax #-}

    import Prelude

    class HasField x r a | x r -> a where
      hasField :: r -> (a -> r, a)

    getField :: forall x r a . HasField x r a => r -> a
    getField = snd . hasField @x -- Note: a.x = is getField @"x" a.
    setField :: forall x r a . HasField x r a => r -> a -> r
    setField = fst . hasField @x -- Note : a{x = b} is setField @"x" a b.

    data Person = Person { name :: String } deriving Show
    instance HasField "name" Person String where
        hasField r = (\x -> case r of Person { .. } -> Person { name = x, .. }, name r)

    data Company = Company { company :: String, owner :: Person } deriving Show
    instance HasField "company" Company String where
        hasField r = (\x -> case r of Company { .. } -> Company { company = x, .. }, company r)
    instance HasField "owner" Company Person where
        hasField r = (\x -> case r of Company { .. } -> Company { owner = x, .. }, owner r)

    main = do
      let c = Company {company = "Acme Corp.", owner = Person { name = "Wile E. Coyote" }}

      -- Top-level update
      print $ c{company = "Acme United"} -- Company {company = "Acme United", owner = Person {name = "Wile E. Coyote"}}

      -- Nested update
      print $ c{owner.name = "Walter C. Johnsen"} -- Company {company = "Acme Corp.", owner = Person {name = "Walter C. Johnsen"}}

      -- Punned update
      let name = "Walter C. Johnsen"
      print $ c{owner.name}  -- Company {company = "Acme Corp.", owner = Person {name = "Walter C. Johnsen"}}

`OverloadedRecordUpdate` works by desugaring record `.` update expressions to expressions involving the functions `setField` and `getField`. Note that all record updates will be desugared to `setField` expressions whether they use `.` notation or not.

At this time, `RebindableSyntax` must be enabled when `OverloadedRecordUpdate` is and users are required to provide definitions for `getField` and `setField`. We anticipate this restriction to be lifted in a future release of GHC with builtin support for `setField`.