|
# Declared Overloaded Record Fields (DORF)
|
|
# Declared Overloaded Record Fields (DORF)
|
|
|
|
|
|
|
|
## Thumbnal Sketch
|
|
|
|
|
|
|
|
|
|
|
|
This proposal is addressing the narrow issue of **namespacing for record field names** by allowing more than one record in the same module to share a field name. Specifically the record field name is overloaded so that:
|
|
|
|
|
|
|
|
- Many record types can be declared in the same module to share the field name.
|
|
|
|
- The field name can be exported so that records in other modules can share it.
|
|
|
|
|
|
|
|
|
|
|
|
The export/import is under usual H98 namespace and module/qualification control, so that when exporting a record type:
|
|
|
|
|
|
|
|
- Some fields can be both read and updated;
|
|
|
|
- Some can be read-only;
|
|
|
|
- Some can be completely hidden.
|
|
|
|
|
|
|
|
|
|
|
|
This proposal introduces several new elements of syntax, all of which desugar to use well-established extensions to ghc. The approach has been proptotyped in ghc v 7.2.1. In particular:
|
|
|
|
|
|
|
|
- The field name overloading is implemented through usual class and instance mechanisms.
|
|
|
|
- Field selectors are ordinary functions named for the field (but overloaded rather than H98's monomorphic), so field selection is regular function application.
|
|
|
|
|
|
|
|
### Implementation: the `Has` class, and methods `get` and `set`
|
|
|
|
|
|
|
|
|
|
|
|
Record declarations, instead of generating a (monomorphic) selector function named for the field, generate a `Has` instance for each record type/field combination. A data declaration, its `Has` instance, and examples of use:
|
|
|
|
|
|
|
|
```wiki
|
|
|
|
data Customer = Cust{ customer_id :: Int, ... }
|
|
|
|
instance (t ~ Int) => Has Customer Proxy_customer_id t where
|
|
|
|
get Cust{ customer_id } _ = customer_id -- DisambiguateRecordFields style
|
|
|
|
set _ x Cust{ .. } = Cust{ customer_id = x, .. } -- RecordWildCards and NamedFieldPuns
|
|
|
|
|
|
|
|
myCust :: Customer
|
|
|
|
... (customer_id myCust) ... -- field selection is func apply
|
|
|
|
... myCust{ customer_id = 27 } -- polymorphic record update
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Note that the mechanism uses a Proxy as the type 'peg' for a field (this is the wildcard argument to `get` and `set`):
|
|
|
|
|
|
|
|
- The Proxy must be declared once, and is then under regular name control.
|
|
|
|
- The field selector function also must be declared once, using the Proxy.
|
|
|
|
|
|
|
|
```wiki
|
|
|
|
data Proxy_customer_id -- phantom
|
|
|
|
customer_id :: r{ customer_id :: Int }
|
|
|
|
customer_id r = get r (undefined :: Proxy_customer_id)
|
|
|
|
|
|
|
|
set Proxy_customer_id 27 myCust
|
|
|
|
```
|
|
|
|
|
|
|
|
- The field selector function is an (overloaded) call to the `get` function, it's type is a function from a record to
|
|
|
|
|
|
|
|
|
|
Explained in 5 wiki pages (these proposals are linked but somewhat orthogonal):
|
|
Explained in 5 wiki pages (these proposals are linked but somewhat orthogonal):
|
|
|
|
|
... | | ... | |