Changes between Version 2 and Version 3 of Records/OverloadedRecordFields/Plan

Jun 17, 2013 4:41:54 PM (4 years ago)



  • Records/OverloadedRecordFields/Plan

    v2 v3  
    4 == Introduction ==
     4== Design ==
    6 Motivating example:
     6'''SLPJ''' this section should be a careful design specfication.
     8=== Motivating example ===
    1820If the flag `-XOverloadedRecordFields` is enabled, a new form of 'record field' constraints `r { x :: t } :: Constraint` are available where `r` and `t` are types, while `x` is a literal string.  These are not typeclass constraints and do not have instances as such (though see the discussion below about virtual record fields). They can appear in contexts in the usual way (that is, they are a new primitive, like equality constraints or implicit parameter constraints). Multiple fields may be written comma-separated in a single constraint as in `r { x :: t, y :: u }`.
     22'''SLPJ note'''.  I think it's more helpful to introduce it as a type-class constraint that happens to have convenient concrete syntax:
     24class Has (r::*) (s::Symbol) (t::*) where
     25  getFld :: r -> t
     27-- data T a = MkT { x :: [a] }
     28instance (b ~ [a]) => Has (T a) "r" b where
     29  getFld (MkT { x = x }) = x
     31The `(b ~ [a])` in the instance is important, so that we get an instance match from the first two fields only.
     33Then we have convenient syntax for `(Has r "x" t)`, namely `r { x::t }`.  Moreover, we get convenient syntax for conjunctions: `(Has r "x" tx, Has r "y" ty)` has shorthand `r { x::tx, y:: ty }`.
     35Don't forget that the `r` might be an arbitrary type not just a type variable or type constructor.  For example, `(Has (T (Maybe b)) "x" [Maybe v])` is a perfectly fine (and soluble) constraint.  I suppose that its shorthand looks like `T (Maybe v) { x :: [Maybe v] }`
     36'''End of SLPJ'''
    2038Record field constraints are introduced by projections, which are written using a new left-associative infix operator `(.>)`.  That is, if `e :: r` then `e.>x :: r { x :: t } => t`.  This operator must always be applied to (at least) its second argument, so `(.>)` is invalid but `(.>x) :: forall a b . a { x :: b } => a -> b`.
    2240A constraint `R { x :: t }` is solved if `R` is a datatype that has a field `x` of type `t` in scope. (More precisely, if `R` contains `x :: s` then `t` must be an instance of `s`.) An error is generated if `R` has no field called `x`, it has the wrong type, or the field is not in scope. Otherwise, the new constraints are handled by the solver just like other types of constraint.
     42If multiple constructors for a single datatype use the same field name, all occurrences must have exactly the same type, as at present.
     44=== Record selectors ===
    2446Optionally, we could [wiki:Records/DeclaredOverloadedRecordFields/NoMonoRecordFields add a flag `-XNoMonoRecordFields`] to disable the generation of the usual monomorphic record field selector functions.  This is not essential, but would free up the namespace for other record systems (e.g. '''data-lens'''). Note that `-XOverloadedRecordFields` will generate monomorphic selectors by default for backwards compatibility reasons, but they will not be usable if multiple selectors with the same name are in scope.
    2648When either flag is enabled, the same field label may be declared repeatedly in a single module (or a label may be declared when a function of that name is already in scope).
    28 If multiple constructors for a single datatype use the same field name, all occurrences must have exactly the same type, as at present.