Changes between Version 70 and Version 71 of Records/OverloadedRecordFields/Implementation


Ignore:
Timestamp:
Oct 16, 2013 8:10:17 AM (6 months ago)
Author:
adamgundry
Comment:

update to latest design

Legend:

Unmodified
Added
Removed
Modified
  • Records/OverloadedRecordFields/Implementation

    v70 v71  
    55== The basic idea == 
    66 
    7 The `Has` and `Upd` classes, and `GetResult` and `SetResult` type families, are defined in the module [https://github.com/adamgundry/packages-base/blob/overloaded-record-fields/GHC/Records.hs GHC.Records] in the `base` package. 
     7The `Has` and `Upd` classes, and `FldTy` and `UpdTy` type families, are defined in the module [https://github.com/adamgundry/packages-base/blob/overloaded-record-fields/GHC/Records.hs GHC.Records] in the `base` package. 
    88 
    99Typechecking a record datatype still generates record selectors, but their names have a `$sel` prefix and end with the name of their type. Moreover, instances for the classes and type families are generated. For example, 
     
    1919$sel:x:T (MkT x) = x 
    2020 
    21 $dfHasTx :: forall a . a ~ Int => Has T "x" a -- corresponds to the Has instance decl 
     21$dfHasTx :: Has T "x" -- corresponds to the Has instance decl 
    2222$dfHasTx = Has { getField _ = $sel_x_T } 
    2323 
     
    2525$dfUpdTx = Upd { setField _ s e = s { x = e } } 
    2626 
    27 axiom TFCo:R:GetResultTx : GetResult T "x" = Int   -- corresponds to the GetResult type family instance 
    28 axiom TFCo:R:SetResultTx : SetResult T "x" Int = T -- corresponds to the SetResult type family instance 
     27axiom TFCo:R:FldTy:T:x : FldTy T "x" = Int   -- corresponds to the FldTy type family instance 
     28axiom TFCo:R:UpdTy:T:x : UpdTy T "x" Int = T -- corresponds to the UpdTy type family instance 
    2929}}} 
    3030 
     
    3737{{{ 
    3838data FieldLbl a = FieldLabel { 
    39       flLabel     :: FieldLabelString, -- ^ Label of the field 
    40       flSelector  :: a,                -- ^ Record selector function 
    41       flInstances :: FldInsts a        -- ^ Instances for overloading 
     39      flLabel        :: FieldLabelString, -- ^ Label of the field 
     40      flIsOverloaded :: Bool,             -- ^ Is this field overloaded? 
     41      flSelector     :: a,                -- ^ Record selector function 
     42      flHasDFun      :: a,                -- ^ DFun for Has class instance 
     43      flUpdDFun      :: a,                -- ^ DFun for Upd class instance 
     44      flFldTyAxiom   :: a,                -- ^ Axiom for FldTy family instance 
     45      flUpdTyAxiom   :: a                 -- ^ Axiom for UpdTy family instance 
    4246    } 
    4347 
    4448type FieldLabelString = FastString 
    4549type FieldLabel = FieldLbl Name 
    46  
    47 data FldInsts a = FldInsts { fldInstsHas :: a 
    48                            , fldInstsUpd :: a 
    49                            , fldInstsGetResult :: a 
    50                            , fldInstsSetResult :: a } 
    51 }}} 
    52  
    53 Every field has a label (`FastString`), selector, and names for the dfuns and axioms (stored together in the `FldInsts` record). The `dcFields` field of `DataCon` stores a list of `FieldLabel`, whereas the `ifConFields` field of `IfaceConDecl` stores a list of `FieldLbl OccName`. 
     50}}} 
     51 
     52For this purpose, a field "is overloaded" if it was defined in a module with `-XOverloadedRecordFields` enabled, so its selector name differs from its label. Every field has a label (`FastString`), selector, and names for the dfuns and axioms. The `dcFields` field of `DataCon` stores a list of `FieldLabel`, whereas the `ifConFields` field of `IfaceConDecl` stores a list of `FieldLbl OccName`. 
    5453 
    5554 
     
    6059{{{ 
    6160data AvailInfo      = Avail Name | AvailTC Name [Name] AvailFields 
    62 data AvailFlds name = NonOverloaded [name] | Overloaded [(FieldLabelString, name)] 
     61type AvailFlds name = [AvailFld name] 
     62type AvailFld name  = (name, Maybe FieldLabelString) 
    6363type AvailFields    = AvailFlds Name 
    64 }}} 
    65  
    66 The `AvailTC` constructor represents a type and its pieces that are in scope. Record fields are now stored separately in the third argument. If the fields are not overloaded, we store only the selector names, whereas if they are overloaded, we store the labels as well. The `IEThingWith name [name] (AvailFlds name)` constructor of `IE` represents a thing that can be imported or exported, and also has a separate argument for fields. 
     64type AvailField     = AvailFld Name 
     65}}} 
     66 
     67The `AvailTC` constructor represents a type and its pieces that are in scope. Record fields are now stored separately in the third argument. If a field is not overloaded, we store only its selector name (the second component of the pair is `Nothing`), whereas if it is overloaded, we store the label as well. The `IEThingWith name [name] (AvailFlds name)` constructor of `IE` represents a thing that can be imported or exported, and also has a separate argument for fields. 
    6768 
    6869Note that a `FieldLabelString` and parent is not enough to uniquely identify a selector, because of data families: if we have 
     
    7879}}} 
    7980 
    80 then `N` exports two different selectors with the `FieldLabelString` `"foo"`. 
     81then `N` exports two different selectors with the `FieldLabelString` `"foo"`. Similar tricks can be used to generate parents that have a mixture of overloaded and non-overloaded fields as children. 
    8182 
    8283 
    8384=== `Parent` and `GlobalRdrElt` === 
    8485 
    85 The `Parent` type has an extra constructor `FldParent Name FastString` that stores the parent `Name` and the field label `FastString`. The `GlobalRdrElt` (`GRE`) for a field stores the selector name directly, and uses the `FldParent` constructor to store the field. Thus a field `x` of type `T` gives rise this entry in the `GlobalRdrEnv`: 
    86  
    87 {{{ 
    88 x |->  GRE $sel:x:T (FldParent T x) LocalDef 
    89 }}} 
    90  
    91 Note that the `OccName` used when adding a GRE to the environment (`greOccName`) now depends on the parent field: for `FldParent` it is the field label rather than the selector name. 
     86The `Parent` type has an extra constructor `FldParent Name (Maybe FieldLabelString)` that stores the parent `Name` and the field label. The `GlobalRdrElt` (`GRE`) for a field stores the selector name directly, and uses the `FldParent` constructor to store the field. Thus a field `x` of type `T` gives rise this entry in the `GlobalRdrEnv`: 
     87 
     88{{{ 
     89x |->  GRE $sel:x:T (FldParent T (Just x)) LocalDef 
     90}}} 
     91 
     92Note that the `OccName` used when adding a GRE to the environment (`greOccName`) now depends on the parent field: for `FldParent` it is the field label, if present, rather than the selector name. 
    9293 
    9394 
    9495== Source expressions == 
    9596 
    96 The `HsExpr` type has extra constructors `HsOverloadedRecFld FieldLabelString` and `HsSingleRecFld RdrName id`. When `-XOverloadedRecordFields` is enabled, and `rnExpr` encounters `HsVar "x"` where `x` refers to multiple `GRE`s that are all record fields, it replaces it with `HsOverloadedRecFld "x"`. When the typechecker sees `HsOverloadedRecFld x` it emits a wanted constraint `Has alpha x beta` and returns type `alpha -> beta` where `alpha` and `beta` are fresh unification variables. 
     97The `HsExpr` type has extra constructors `HsOverloadedRecFld FieldLabelString` and `HsSingleRecFld RdrName id`. When `-XOverloadedRecordFields` is enabled, and `rnExpr` encounters `HsVar "x"` where `x` refers to multiple `GRE`s that are all record fields, it replaces it with `HsOverloadedRecFld "x"`. When the typechecker sees `HsOverloadedRecFld "x"` it converts it into `accessField (proxy# :: Proxy "x")`. 
    9798 
    9899When the flag is not enabled, `rnExpr` turns an unambiguous record field `foo` into `HsSingleRecFld foo $sel_foo_T`. The point of this constructor is so we can pretty-print the field name (as the user typed it, hence a `RdrName`), but store the selector name for typechecking. 
     
    193194 
    194195{{{ 
    195 -- setField :: proxy "x" -> W (a, b) -> a -> W (a, b) 
     196-- setField :: Proxy# "x" -> W (a, b) -> a -> W (a, b) 
    196197setField _ s e = s { x = e } 
    197198}}} 
     
    221222 
    222223{{{ 
    223 instance t ~ Int => Has (F Int) "foo" t 
    224 instance t ~ Bool => Has (F Bool) "foo" t 
     224instance Has (F Int) "foo" 
     225instance Has (F Bool) "foo" 
    225226}}} 
    226227 
     
    244245 
    245246* The `minf_exports` field of `ModuleInfo` is now of type `[AvailInfo]` rather than `NameSet`, as this provides accurate export information. An extra function `modInfoExportsWithSelectors` gives a list of the exported names including overloaded record selectors (whereas `modInfoExports` includes only non-mangled selectors). 
     247* The `HsExpr`, `hsRecField` and `ConDeclField` AST types have changed as described above. 
    246248 
    247249 
    248250== To do == 
     251 
     252* The definition of `tcFldInsts` is currently wrong, because with the new design, the constraint solver needs to generate evidence bindings. Where should these go? It should be possible to fuse `makeRecFldInstsFor` and `tcFldInsts`, or just generate and typecheck binds, using `tcValBinds` or similar for the typechecking. 
    249253 
    250254* Where should `TcBuiltInSynFamily` live? Could it be a fixed enumeration? 
     
    256260  2. `tcHsBootSigs` should populate it with `val_ids` and return an updated `TcGblEnv` 
    257261  3. Add a new field `tcg_boot_ids :: Bag Id` to `TcGblEnv` and pass `val_ids` to `mkBootModDetailsTc` that way, so it doesn't need to use the `TypeEnv` 
    258 * We now generate `r { foo :: ... }` in the pretty-printer, but should we accept it in the parser?  What if the supressed type is `GetResult s "foo"` for a different type s? 
    259 * Fuse `makeRecFldInstsFor` and `tcFldInsts`, or just generate and typecheck binds.  Use `tcValBinds` or similar for the typechecking. 
    260  
    261 * Consider defaulting `Accessor p` to `p = (->)`, and defaulting `Has r "f" t` constraints where there is only one datatype with a field `f` in scope. 
     262* Pretty-printing needs to be sorted out for the new design with a two-parameter Has class 
     263 
     264* Consider defaulting `Accessor p r n` to `p = (->)`, and defaulting `Has r "x"` constraints where there is only one datatype with a field `x` in scope. 
    262265* We could add `HsVarOut RdrName id` instead of `HsSingleRecFld` (or perhaps rename `HsVar` to `HsVarIn`). This would also be useful to recall how the user referred to something. 
    263266* Add syntax for record projection, perhaps using # since it shouldn't conflict with `MagicHash`?