Skip to content

How to disambiguate data family instances with duplicate record fields?

Summary

I have been upgrading from ghc-8.10.7 to ghc-9.2.5 and dealing with the -Wambiguous-fields warning as it is deprecating:

This will not be supported by -XDuplicateRecordFields in future releases of GHC.

-XOverloadedRecordDot is very nice for field access. For record updates I've been qualifying field names to avoid the ambiguity.

I found a data family with multiple instances in the same module, each a record with -XDuplicateRecordFields, and could not find a way to import from this module qualified in order to disambiguate a record update.

Steps to reproduce

See the repo https://github.com/typechecker/data-family-record-dot for these code snippets:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DuplicateRecordFields #-}
module DataFamily where

import Data.Kind

data Choice = A | B

data family Fam :: Choice -> Type

newtype instance Fam A = FamA{ field :: Int }
newtype instance Fam B = FamB{ field :: Bool }
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE RecordWildCards #-}
module RecordUpdate where

import DataFamily (Choice(..))
import qualified DataFamily as WhoIsB (Fam(FamB), Fam(field))

toggleBool :: WhoIsB.Fam B -> WhoIsB.Fam B
toggleBool b@WhoIsB.FamB{..} =
    b{ WhoIsB.field = not field}
$ cabal repl
Resolving dependencies...
Build profile: -w ghc-9.4.4 -O1
In order, the following will be built (use -v for more details):
 - data-family-record-dot-0.1.0.0 (lib) (first run)
Configuring library for data-family-record-dot-0.1.0.0..
Preprocessing library for data-family-record-dot-0.1.0.0..
GHCi, version 9.4.4: https://www.haskell.org/ghc/  :? for help
[1 of 2] Compiling DataFamily       ( src/DataFamily.hs, interpreted )
[2 of 2] Compiling RecordUpdate     ( src/RecordUpdate.hs, interpreted )

src/RecordUpdate.hs:7:1: warning: [-Wunused-imports]
    The qualified import of ‘Fam(field)’
    from module ‘DataFamily’ is redundant
  |
7 | import qualified DataFamily as WhoIsB (Fam(FamB), Fam(field))
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/RecordUpdate.hs:11:8: warning: [-Wambiguous-fields]
    The record update b {WhoIsB.field = not
                                          field} with type DataFamily.R:FamB is ambiguous.
    This will not be supported by -XDuplicateRecordFields in future releases of GHC.
   |
11 |     b{ WhoIsB.field = not field}
   |        ^^^^^^^^^^^^^^^^^^^^^^^^
Ok, two modules loaded.

Note that if I followed the advice of the first warning and remove the qualified import of Fam(field) then I get an error.

- import qualified DataFamily as WhoIsB (Fam(FamB), Fam(field))
+ import qualified DataFamily as WhoIsB (Fam(FamB))
src/RecordUpdate.hs:11:8: error:
    Not in scope: ‘WhoIsB.field’
    Suggested fix:
      Perhaps you want to add ‘field’ to the import list in the import of
      ‘DataFamily’ (src/RecordUpdate.hs:7:1-49).
   |
11 |     b{ WhoIsB.field = not field}
   |  

Expected behavior

I'd expect to be able to use a qualified import to disambiguate. Is there a way? A workaround is to move one of the data family instances to another module, side-stepping the duplicate record field altogether, but that has import consequences for other consumers of the module (now two imports when there was one required to import all instances).

Environment

ghc-9.4.4 and ghc-9.2.5 are the same here.

Edited by Phil de Joux
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information