[GHC] #16232: Add setField to HasField

#16232: Add setField to HasField -------------------------------------+------------------------------------- Reporter: adamgundry | Owner: (none) Type: feature | Status: new request | Priority: normal | Milestone: 8.10.1 Component: Compiler | Version: 8.7 (Type checker) | Keywords: ORF | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- This ticket is to track the implementation of https://github.com/ghc- proposals/ghc-proposals/blob/master/proposals/0042-record-set-field.rst I've made a start on the implementation but have a question on which I'd appreciate some input: how should the dictionary for `HasField` be generated? To recap, recall that at present, `HasField x r a` is coercible to `r -> a` so the dictionary can be constructed merely by taking the selector function for the field and wrapping it in an appropriate coercion. With the proposal, `HasField x r a` will instead be represented as `r -> (a -> r, a)` where the first component of the tuple is an update function. The problem is how to define this update function in Core. This function should perform case analysis on the record data type, where each case replaces the value of the field being updated and preserves all the other fields. For example, given a data type `data T = MkT { foo :: Int, bar :: Bool }` we need to generate {{{#!hs \ r x -> case r of MkT {foo = _, bar = bar} -> MkT { foo = x, bar = bar } }}} The most obvious approach is to generate well-typed Core for the update function directly, but this seems to be rather complex, in particular because of the worker/wrapper distinction, as one ends up reconstructing much of the typechecking/desugaring for record pattern matching and construction. This also seems like a lot of work to do every time a `HasField` constraint is solved. Would it be reasonable to generate update functions for fields at definition sites, as we do for selector functions? I've implemented this in the past, and it is relatively simple to generate renamed syntax to feed in to the type-checker. However, this would add some overhead for every field, even if `HasField` was not subsequently used, and would require some naming scheme for update functions. Or are there other options? Is there some way to solve a `HasField` constraint and construct its dictionary by emitting renamed syntax for subsequent type-checking, such that subsequently solving similar constraints will use the same dictionary? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/16232 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#16232: Add setField to HasField -------------------------------------+------------------------------------- Reporter: adamgundry | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: 8.10.1 Component: Compiler (Type | Version: 8.7 checker) | Resolution: | Keywords: ORF Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by mpickering): It seems quite straightforward to generate the necessary core. I think you mean that you would generate: {{{ \ r x -> case r of MkT _ bar -> MkT x bar }}} You don't need to mention any wired-in Ids or anything so it seems simple? It also doesn't seem like a lot of work to me in the grand scheme of things so I wouldn't mind doing it every time one of these constraints is solved. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/16232#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#16232: Add setField to HasField -------------------------------------+------------------------------------- Reporter: adamgundry | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: 8.10.1 Component: Compiler (Type | Version: 8.7 checker) | Resolution: | Keywords: ORF Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by simonpj): I suggest taking the direct path, and generate an update function for each field. Its more work than Matthew says because we may need to evaluate the argument (for strict constructors) or unbox it (if the argument is UNPACKed). This would ''replace'' the selector function would it not? The new function is a selector and update function? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/16232#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#16232: Add setField to HasField -------------------------------------+------------------------------------- Reporter: adamgundry | Owner: adamgundry Type: feature request | Status: new Priority: normal | Milestone: 8.10.1 Component: Compiler (Type | Version: 8.7 checker) | Resolution: | Keywords: ORF Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by adamgundry): * owner: (none) => adamgundry Comment:
I suggest taking the direct path, and generate an update function for each field.
Sorry, to be clear, do you mean the approach of generating renamed syntax at definition sites?
Its more work than Matthew says because we may need to evaluate the argument (for strict constructors) or unbox it (if the argument is UNPACKed).
Exactly, perhaps my example didn't do a good job of conveying the awkward points here. Let me see if I understand correctly what generating Core directly needs to do in the general case: * When we pattern match in Core, we match on the *worker* (binding its existential tyvars, theta and the arguments as given by `dataConInstSig`). * We can use `dataConBoxer` to build let-bindings for the arguments to the wrapper out of the bound variables from matching on the worker. * We need to construct an application of the *wrapper* to appropriate boxed arguments, replacing the one that corresponds to the field being updated with the new value. I don't understand very clearly how to do this. In particular, I'm not sure how to figure out the order in which to instantiate type variables and dictionaries in the wrapper's type. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/16232#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#16232: Add setField to HasField -------------------------------------+------------------------------------- Reporter: adamgundry | Owner: adamgundry Type: feature request | Status: new Priority: normal | Milestone: 8.10.1 Component: Compiler (Type | Version: 8.7 checker) | Resolution: | Keywords: ORF Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by mpickering): You are right that does seem a bit tricky. Another possibility is generating renamed syntax when solving the constraint then type checking it and desugaring it using `tcExpr` and `dsExpr` to generate the necessary evidence? This is all possible to do in `ClsInst`. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/16232#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#16232: Add setField to HasField -------------------------------------+------------------------------------- Reporter: adamgundry | Owner: adamgundry Type: feature request | Status: new Priority: normal | Milestone: 8.10.1 Component: Compiler (Type | Version: 8.7 checker) | Resolution: | Keywords: ORF Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by simonpj):
Sorry, to be clear, do you mean the approach of generating renamed syntax at definition sites?
Yes -- essentially replacing the stuff where we generate record selectors by stuff that generates this compound selector/updater function; plus perhaps generating the legacy selector function from that. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/16232#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#16232: Add setField to HasField -------------------------------------+------------------------------------- Reporter: adamgundry | Owner: adamgundry Type: feature request | Status: new Priority: normal | Milestone: 8.10.1 Component: Compiler (Type | Version: 8.7 checker) | Keywords: ORF, Resolution: | GHCProposal Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by RyanGlScott): * keywords: ORF => ORF, GHCProposal -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/16232#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC