Changes between Version 1 and Version 2 of Records/OverloadedRecordFields/Design


Ignore:
Timestamp:
Apr 22, 2014 9:48:39 AM (15 months ago)
Author:
simonpj
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Records/OverloadedRecordFields/Design

    v1 v2  
    6969The bare type variable `b` in the instance head is important, so that we get an instance match from the first two parameters only, then the equality constraint `(b ~ [a])` improves `b`. For example, if the constraint `Has (T c) "x" d` is encountered during type inference, the instance will match and generate the constraints `(a ~ c, b ~ d, b ~ [a])`. Moreover, the `FldTy` type family ensures that the third parameter is functionally dependent on the first two, which is needed to [#Troubleinparadise avoid ambiguity errors when composing overloaded fields].  
    7070 
    71 The reason for using a three-parameter class, rather than just two parameters and a type family, is to support the syntactic sugar and improve type inference error messags. With a two-parameter class we could easily end up inferring types like the following, and it would be hard to reapply the sugar:  
     71The reasons for using a three-parameter class, rather than just two parameters and a type family, are (a) to support the syntactic sugar and (b) improve type inference error messages. With a two-parameter class we could easily end up inferring types like the following, and it would be hard to reapply the sugar:  
    7272 
    7373{{{  
     
    8181=== Representation hiding === 
    8282 
    83 At present, a datatype in one module can declare a field, but if the selector function is not exported, then the field is hidden from clients of the module. It is important to support this. Typeclasses in general have no controls over their scope, but for implicitly generated `Has` instances, the instance is available for a module if `-XOverloadedRecordFields` is enabled for that module and the record field selector function is in scope. Instances are not exported from the module that defines the datatype, but are created implicitly when needed by the typechecker. 
     83At present, a datatype in one module can declare a field, but if the selector function is not exported, then the field is hidden from clients of the module. It is important to support this. Typeclasses in general have no controls over their scope, but we treat the implicitly-generated `Has` instances differently.   
     84  
     85 * Instances are not exported from the module that defines the datatype, but instead are created implicitly when needed by the typechecker.  
     86 
     87 * An implicitly-generated `Has` instance for a field `x` of data type `T` is available in a module `M` if 
     88   * `-XOverloadedRecordFields` is enabled for module `M` and  
     89   * The record field selector function `x` is in scope.  
     90 
     91Notice that 
     92 * The data type `T` might be defined locally in `M`, or imported. 
     93 * If `T` is imported it does not matter whether `-XOverloadedRecordFields` is enabled in the module where `T` was defined. 
     94 
     95All this is very like the special treatment of `Coercible` instances (see [http://research.microsoft.com/en-us/um/people/simonpj/papers/ext-f/ Safe Coercions]). 
    8496 
    8597This enables representation hiding: just like at present, exporting the field selector permits access to the field. For example, consider the following module: 
    8698 
    8799{{{ 
    88 module M ( R(x) ) where 
     100module M ( R(x), S ) where 
    89101 
    90102data R = R { x :: Int } 
     
    94106Any module that imports `M` will have access to the `x` field from `R` but not from `S`, because the instance `Has R "x" Int` will be available but the instance `Has S "x" Bool` will not be. Thus `R { x :: Int }` will be solved but `S { x :: Bool }` will not. 
    95107 
    96  
    97 === Multiple modules and automatic instance generation === 
    98  
    99 Note that `Has` instances are generated on a per-module basis, using the fields that are in scope for that module, and automatically generated instances are never exported. Thus it doesn't matter whether `-XOverloadedRecordFields` was on in the module that defined the datatype. The availability of the instances in a particular module depends only on whether the flag is enabled for that module. 
    100  
    101108Suppose module `M` imports module `N`, `N` imports module `O`, and only `N` has the extension enabled. Now `N` can project any field in scope (including those defined in `O`), but `M` cannot access any `Has` instances.  
    102109 
    103110This means that 
    104  * the extension is required whenever a `Has` constraint must be solved; 
     111 * the extension `-XOverloadedRecordFields` is required whenever a `Has` constraint must be solved; 
     112 * records defined in existing modules (or other packages) without the extension can still be overloaded. 
    105113 * no new mechanism for hiding instances is required; and 
    106  * records defined in existing modules (or other packages) without the extension can still be overloaded. 
    107  
    108114 
    109115=== Higher-rank fields ===