Changes between Version 89 and Version 90 of Records/OverloadedRecordFields/Implementation


Ignore:
Timestamp:
Oct 22, 2015 8:24:16 PM (4 years ago)
Author:
adamgundry
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Records/OverloadedRecordFields/Implementation

    v89 v90  
    1 = OverloadedRecordFields implementation notes =
     1= `OverloadedRecordFields` implementation notes =
    22
    3 '''This page gives implementation details of the [wiki:Records/OverloadedRecordFields OverloadedRecordFields] extension.  It is targeted at GHC hackers.'''
     3The implementation notes are now broken down by part:
    44
    5  * See the [wiki:Records/OverloadedRecordFields/Redesign redesign page] for a more gentle introduction.
    6  * See [http://www.well-typed.com/blog/2015/03/overloadedrecordfields-revived/ Adam's post on the Well-Typed blog]
    7 
    8 Following the 2015 redesign, we have three separate components to implement, which will be described (and implemented) in order:
    9 
    10  * the `DuplicateRecordFields` extension, which permits the same field name to be used multiple times in the same module, but only where unambiguous;
    11  * the `OverloadedLabels` extension, to enable the `#x` syntax;
    12  * the `HasField` and `FieldUpdate` typeclasses, with special-purpose constraint solving behaviour, which do not require a language extension.
    13 
    14 As of March 2015, work is progressing on the implementation. Part 1 (the `DuplicateRecordFields` extension) is available at Phab:D761 and being reviewed. Part 2 (the `OverloadedLabels` extension) is nearly ready, and part 3 will be implemented after the first two parts have been completed. Note that all the parts are useful in isolation.
    15 
    16 == 1. The `DuplicateRecordFields` extension ==
    17 
    18 See [wiki:Records/OverloadedRecordFields/DuplicateRecordFields#Implementation separate notes of the implementation of DuplicateRecordFields].
    19 
    20 
    21 == 2. The `OverloadedLabels` extension ==
    22 
    23 See [wiki:Records/OverloadedRecordFields/OverloadedLabels#Implementation separate notes of the implementation of OverloadedLabels].
    24 
    25 == 3. The magic type classes ==
    26 
    27 The `HasField` and `FieldUpdate` classes, and `FieldType` and `UpdatedRecordType` type families, will be defined in the module `GHC.Records` in the `base` package.  Contrary to the previous design, we will not generate any dfuns/axioms for these classes *at all*.  Instead, the typechecker will implicitly create evidence as required.  This gets rid of a whole lot of complexity.
    28 
    29 The only additional things that need to be generated at datatype declarations are updater functions (one per field), which correspond to the selector functions that are already generated.  So for example
    30 
    31 {{{
    32 data T = MkT { x, y :: Int }
    33 }}}
    34 
    35 will generate
    36 
    37 {{{
    38 $sel:x:T :: T -> Int
    39 $sel:x:T (MkT x _) = x
    40 
    41 $upd:x:T :: T -> Int -> T
    42 $upd:x:T (MkT _ y) x = MkT x y
    43 }}}
    44 
    45 The updater function will always have a name prefixed with `$upd:`, regardless of whether `OverloadedRecordFields` is enabled.
    46 
    47 
    48 === GADT record updates ===
    49 
    50 Consider the example
    51 
    52 {{{
    53 data W a where
    54     MkW :: a ~ b => { x :: a, y :: b } -> W (a, b)
    55 }}}
    56 
    57 It would be nice to generate
    58 
    59 {{{
    60 -- $upd:x:W :: W (a, b) -> a -> W (a, b)
    61 $upd:x:W s e = s { x = e }
    62 }}}
    63 
    64 but this record update is rejected by the typechecker, even though it is perfectly sensible, because of #2595. The currently implemented workaround is instead to generate the explicit update
    65 
    66 {{{
    67 $upd:x:W (MkW _ y) x = MkW x y
    68 }}}
    69 
    70 which is fine, but rather long-winded if there are many constructors or fields. Essentially this is doing the job of the desugarer for record updates.
    71 
    72 Note that `W` does not admit type-changing single update for either field, because of the `a ~ b` constraint. Without it, though, type-changing update should be allowed.
    73 
    74 
    75 === Unused bindings ===
    76 
    77 Unused local bindings are tricky in the presence of the magic type classes, as the following example illustrates:
    78 
    79 {{{
    80 module M (f)
    81   data S = MkS { foo :: Int }
    82   data T = MkT { foo :: Int }
    83 
    84   f = #foo (MkS 3)
    85   g x = #foo x
    86 }}}
    87 
    88 The renamer calculates the free variables of each definition, to produce a list of `DefUses`. The typechecker will discover that `f` uses only `S(foo)` while `g` uses neither. The simplest thing might be to make an occurrence of an overloaded field in an expression return as free variables all the selectors it might refer to. This will sometimes fail to report unused local bindings: in the example, it will not spot that `T(foo)` is unused.
    89 
    90 TODO: this needs some thought in the new story. An overloaded label might not have anything to do with fields. Moreover, what if the typechecker solves a `HasField` constraint that was introduced without using the overloaded label syntax? Can we defer unused local binding reporting somehow?
     5 1. [wiki:Records/OverloadedRecordFields/DuplicateRecordFields#Implementation DuplicateRecordFields]
     6 2. [wiki:Records/OverloadedRecordFields/OverloadedLabels#Implementation OverloadedLabels]
     7 3. [wiki:Records/OverloadedRecordFields/MagicClasses#Implementation Magic classes]