.. _duplicate-record-fields: Duplicate record fields ----------------------- .. extension:: DuplicateRecordFields :shortdesc: Allow definition of record types with identically-named fields. :implies: :extension:`DisambiguateRecordFields` :since: 8.0.1 Allow definition of record types with identically-named fields. Going beyond :extension:`DisambiguateRecordFields` (see :ref:`disambiguate-fields`), the :extension:`DuplicateRecordFields` extension allows multiple datatypes to be declared using the same field names in a single module. For example, it allows this: :: module M where data S = MkS { x :: Int } data T = MkT { x :: Bool } Uses of fields that are always unambiguous because they mention the constructor, including construction and pattern-matching, may freely use duplicated field names. For example, the following are permitted (just as with :extension:`DisambiguateRecordFields`): :: s = MkS { x = 3 } f (MkT { x = b }) = b Field names used as selector functions or in record updates must be unambiguous, either because there is only one such field in scope, or because a type signature is supplied, as described in the following sections. Selector functions ~~~~~~~~~~~~~~~~~~ Fields may be used as selector functions only if they are unambiguous, so this is still not allowed if both ``S(x)`` and ``T(x)`` are in scope: :: bad r = x r An ambiguous selector may be disambiguated by the type being "pushed down" to the occurrence of the selector (see :ref:`higher-rank-type-inference` for more details on what "pushed down" means). For example, the following are permitted: :: ok1 = x :: S -> Int ok2 :: S -> Int ok2 = x ok3 = k x -- assuming we already have k :: (S -> Int) -> _ In addition, the datatype that is meant may be given as a type signature on the argument to the selector: :: ok4 s = x (s :: S) However, we do not infer the type of the argument to determine the datatype, or have any way of deferring the choice to the constraint solver. Thus the following is ambiguous: :: bad :: S -> Int bad s = x s Even though a field label is duplicated in its defining module, it may be possible to use the selector unambiguously elsewhere. For example, another module could import ``S(x)`` but not ``T(x)``, and then use ``x`` unambiguously. Record updates ~~~~~~~~~~~~~~ In a record update such as ``e { x = 1 }``, if there are multiple ``x`` fields in scope, then the type of the context must fix which record datatype is intended, or a type annotation must be supplied. Consider the following definitions: :: data S = MkS { foo :: Int } data T = MkT { foo :: Int, bar :: Int } data U = MkU { bar :: Int, baz :: Int } Without :extension:`DuplicateRecordFields`, an update mentioning ``foo`` will always be ambiguous if all these definitions were in scope. When the extension is enabled, there are several options for disambiguating updates: - Check for types that have all the fields being updated. For example: :: f x = x { foo = 3, bar = 2 } Here ``f`` must be updating ``T`` because neither ``S`` nor ``U`` have both fields. - Use the type being pushed in to the record update, as in the following: :: g1 :: T -> T g1 x = x { foo = 3 } g2 x = x { foo = 3 } :: T g3 = k (x { foo = 3 }) -- assuming we already have k :: T -> _ - Use an explicit type signature on the record expression, as in: :: h x = (x :: T) { foo = 3 } The type of the expression being updated will not be inferred, and no constraint-solving will be performed, so the following will be rejected as ambiguous: :: let x :: T x = blah in x { foo = 3 } \x -> [x { foo = 3 }, blah :: T ] \ (x :: T) -> x { foo = 3 } Import and export of record fields ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When :extension:`DuplicateRecordFields` is enabled, an ambiguous field must be exported as part of its datatype, rather than at the top level. For example, the following is legal: :: module M (S(x), T(..)) where data S = MkS { x :: Int } data T = MkT { x :: Bool } However, this would not be permitted, because ``x`` is ambiguous: :: module M (x) where ... Similar restrictions apply on import.