Changes between Version 4 and Version 5 of Records/TypePunningDeclaredOverloadedRecordFields
- Timestamp:
- 03/11/12 20:44:35 (14 months ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
Records/TypePunningDeclaredOverloadedRecordFields
v4 v5 25 25 Note that SORF introduces a third argument for the field's resulting type. (This is specifically to support higher-rank typed fields; but despite the complexity it introduces, SORF has no mechanism to __update__ h-r fields.) 26 26 27 TPDORF approaches h-r fields in a different way, which supports __both__ setting and getting those fields. (I'm not claiming this is a ''solution'', more a well-principled work-round. And not a hack. )27 TPDORF approaches h-r fields in a different way, which supports __both__ setting and getting those fields. (I'm not claiming this is a ''solution'', more a well-principled work-round. And not a hack. It is both scalable, and supports class-constrained higher-rank types.) 28 28 29 29 '''The main insight''' is that to manage large-scale data models (in which namespacing becomes onerous, and name sharing would be most beneficial), there are typically strong naming conventions and representation hiding for critical fields. For example: … … 36 36 , lastName :: String 37 37 , ... 38 } sharing ( customer_id, ...) deriving (...) -- new sharing syntax38 } sharing (Customer_id, ...) deriving (...) -- new sharing syntax 39 39 }}} 40 40 41 TPDORF makes a virtue of this punning. (So extend's H98's and NamedFieldPunspunning on the field name.) This allows for some syntactic shortcuts, but still supporting H98-style declaring field names within the record decl for backwards compatibility.41 TPDORF makes a virtue of this punning. (So extend's H98's and `NamedFieldPuns` punning on the field name.) This allows for some syntactic shortcuts, but still supporting H98-style declaring field names within the record decl for backwards compatibility. 42 42 43 43 Here is the `Has` class with instances for the above Customer record, and examples of use: … … 66 66 67 67 customer_id r = get r :: Customer_id -- we can auto-decl this, see below 68 customer_id :: r{ customer_id :: Customer_id } => r -> Customer_id -- type inferred for the function 68 69 69 70 myCust :: Customer -- usual record decl 70 ... myCust{ customer_id = 27 } -- polymorphic record update71 ... myCust{ customer_id = 27, firstName = Fred } -- **polymorphic** record update, no data constr 71 72 ... (customer_id myCust) ... -- field selection is func apply, or: 72 73 ... myCust.customer_id ... -- dot notation is sugar for reverse func apply … … 75 76 Note that the''' `Has` mechanism''' uses '''the field's type itself''' to locate the field within the record: 76 77 * Each field must be a distinct type. 77 * The Type must be declared once (within the scope), and is then under regular name control.[[BR]](Probably you're doing this already for critical fields .)78 * The field selector function also must be declared once, defined punning on the field's type. 78 * The Type must be declared once (within the scope), and is then under regular name control.[[BR]](Probably you're doing this already for critical fields to share.) 79 * The field selector function also must be declared once, defined punning on the field's type.[[BR]](See below for syntactic sugar to declare these.) 79 80 80 81 It is an error to be `sharing` a record field without there being a same-named type in scope. The desugar for the data decl would create the instance to use the Type, but then the instance would fail. 81 82 82 To generate the correct declarations, there is to be a new `fieldLabel` sugar:83 To generate the correct field selector function, there is to be a new deriving class: 83 84 {{{ 84 fieldLabel customer_id :: r -> Int -- new declaration, desugars to Proxy and func: 85 data Proxy_customer_id -- phantom 86 customer_id :: r{ customer_id :: Int } => r -> Int -- r{ ... } is sugar for Has constraint 87 customer_id r = get r (undefined :: Proxy_customer_id) 85 newtype Customer_id = Customer_id Int -- newtype or data decl, same name type and constr 86 deriving (Has, ...) -- generates customer_id function, per above 88 87 89 set (undefined :: Proxy_customer_id) 27 myCust -- record update desugarred from above example 88 set (Customer_id 27) ( -- record update desugarred from above example 89 set (FirstName "Fred") myCust ) -- note nested 90 91 ... myCust{ cust_id, FirstName "Fred" } -- equiv syntax (assuming cust_id :: Customer_id) 90 92 }}} 91 93 92 * (Admittedly, this could get onerous to declare a `fieldLabel` for every field, even the ones that appear in a single record type. See "Option Three: Mixed In-situ and DeclaredORF: " further down this page for a suggestion of using the DORF mechanism to generate one-off H98-style fields.)93 94 94 '''Virtual''' or '''pseudo-''' fields are easy to create and use, because field selection is merely function application . Virtual fields look like ordinary fields (but can't be updated, because there is no `Has` instance):95 '''Virtual''' or '''pseudo-''' fields are easy to create and use, because field selection is merely function application (plus unwrapping for non-shared H98-style fields). Virtual fields look like ordinary fields (but can't be updated, because there is no `Has` instance): 95 96 {{{ 96 97 fullName r = r.firstName ++ " " ++ map toUpper r.lastName -- example adapted from SPJ … … 103 104 '''Technical capabilities''' and limitations for the `Has` class: 104 105 * Monomorphic fields can be `get` and `set`. 105 * Parametric polymorphic fields can be applied in polymorphic contexts, and can be `set` including changing the type of the record. 106 * Higher-ranked polymorphic fields can be applied in polymorphic contexts, but cannot be set -- for the same reasons as under SORF.[[BR]]The instances use equality constraints to 'improve' types up to polymorphic. 107 * `Has` uses type family functions to manage type-changing update, which adds complexity -- see Implementer's view. 106 * Parametric polymorphic fields can be applied in polymorphic contexts, and can be `set` including changing the type of the record.[[BR]](This uses the SetResult type function.) 108 107 * Multiple fields can be updated in a single expression (using familiar H98 syntax), but this desugars to nested updates, which is inefficient. 109 108 * Pattern matching and record creation using the data constructor prefixed to { ... } work as per H98 (using `DisambiguateRecordFields` and friends). 109 * Higher-ranked polymorphic fields (including class-constrained) can be applied in polymorphic contexts, and can be set -- __providing__ they are wrapped in a newtype. 110 110 111 111 .
