Updating a record using RecordDotSyntax results in an error

Viewed 398

Context

If I load the following into ghc-9.2.1-alpha2 which has support for RecordDotSyntax:

{-# LANGUAGE OverloadedRecordDot, OverloadedRecordUpdate, DuplicateRecordFields #-}
----------------------------------------------------------------------
data Point = Point { x :: Double, y :: Double }

instance Show Point where
    show p = "Point { x = " ++ show p.x ++ ", y = " ++ show p.y ++ " }"

p = Point 10 20

I can then run the following in ghci:

ghci> p { x = 30 }
Point { x = 30.0, y = 20.0 }

Cool, it's working!

Issue

However, if I add the following to my test file above:

result =
    let
        a = Point 1 2
        b = a { x = 3 }
    in
        b

and reload, I get the following message:

ghci> :r
[1 of 1] Compiling Main             ( /home/dharmatech/tmp/test-ghc-9.2.0.20210422/point-update-issue.hs, interpreted )

/home/dharmatech/tmp/test-ghc-9.2.0.20210422/point-update-issue.hs:13:13: error:
    RebindableSyntax is required if OverloadedRecordUpdate is enabled.
   |
13 |         b = a { x = 3 }
   |             ^^^^^^^^^^^
Failed, no modules loaded.

What I've tried

If I add RebindableSyntax as the message suggests, I get many more errors which look like this:

/home/dharmatech/tmp/test-ghc-9.2.0.20210422/point-update-issue.hs:3:27: error:
    Not in scope: type constructor or class ‘Double’
  |
3 | data Point = Point { x :: Double, y :: Double }
  |

Question

Is there a way to get this to work? Or is it something that's just not implemented yet?

Update 2021-08-10

If I add the following as alias and Ari suggested:

import Prelude
import GHC.Records

I get the following:

point-update-issue.hs:17:13: error:
    Not in scope: ‘setField’
    Perhaps you meant ‘getField’ (imported from GHC.Records)
   |
17 |         b = a { x = 3 }
   |             ^^^^^^^^^^^
Failed, no modules loaded.
2 Answers

There are two problems here.

  1. You have enabled RebindableSyntax. This allows you to redefine certain behaviour by defining certain functions, otherwise imported from Prelude, in the local scope. Therefore, RebindableSyntax implies NoImplicitPrelude. You need to manually import Prelude, optionally hiding functions you want to override.

    import Prelude hiding (...)
    
  2. You have enabled OverloadedRecordUpdate, an experimental feature from GHC 9.2 that has not yet been stabilized.

    The relevant version of the GHC User's Guide has this to say:

    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.

    The default getField can be imported from GHC.Records, but setField is not currently available, so you have to implement it yourself.

    Have fun!

EDIT 11/08: This answer is mostly incomplete and partly incorrect. See my other answer.

As @alias explained, if you enable RebindableSyntax, the Prelude will not be automatically loaded. Nor will GHC.Records, normally loaded by and required by record syntax extensions.

You'll have to add this:

import Prelude
import GHC.GetRecords
Related