[GHC] #8582: Record syntax for pattern synonyms

#8582: Record syntax for pattern synonyms ------------------------------------+------------------------------------- Reporter: cactus | Owner: cactus Type: feature request | Status: new Priority: normal | Milestone: Component: Compiler | Version: Keywords: | Operating System: Unknown/Multiple Architecture: Unknown/Multiple | Type of failure: None/Unknown Difficulty: Unknown | Test Case: Blocked By: 5144 | Blocking: Related Tickets: | ------------------------------------+------------------------------------- Implement syntax for {{{ pattern Cons{car, cdr} = (car, cdr) }}} which can then be used just like a regular record constructor, so the following are all valid patterns: {{{ Cons (Just x) [] Cons{car = Just x} }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8582 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8582: Record syntax for pattern synonyms -------------------------------------+------------------------------------ Reporter: cactus | Owner: cactus Type: feature request | Status: new Priority: normal | Milestone: Component: Compiler | Version: Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Unknown/Multiple Type of failure: None/Unknown | Difficulty: Unknown Test Case: | Blocked By: 5144 Blocking: | Related Tickets: -------------------------------------+------------------------------------ Comment (by cactus): Now that I am parsing pattern synonym declarations using the pattern parser (using the same trick as used by the data constructor parser), and typechecking a pattern synonym can add deferred bindings, this should at least be somewhat simpler to implement. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8582#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8582: Record syntax for pattern synonyms -------------------------------------+------------------------------------- Reporter: cactus | Owner: cactus Type: feature request | Status: new Priority: normal | Milestone: Component: Compiler | Version: Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: None/Unknown | Unknown/Multiple Blocked By: 5144 | Test Case: Related Tickets: | Blocking: | Differential Revisions: -------------------------------------+------------------------------------- Comment (by blamario): I just ran into this issue. I'm trying to generalize a legacy record type like {{{ data Foo = Foo{bar :: String} }}} to {{{ data GenFoo s = GenFoo{bar :: s} }}} Unfortunately there is no way to provide a backward-compatible interface after this change. I'm hoping with this feature the solution might be as simple as {{{ type Foo = GenFoo String pattern Foo{bar} = GenFoo bar }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8582#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8582: Record syntax for pattern synonyms -------------------------------------+------------------------------------- Reporter: cactus | Owner: cactus Type: feature request | Status: new Priority: normal | Milestone: Component: Compiler | Version: Resolution: | Keywords: Operating System: Unknown/Multiple | PatternSynonyms Type of failure: None/Unknown | Architecture: Blocked By: 5144 | Unknown/Multiple Related Tickets: | Test Case: | Blocking: | Differential Revisions: -------------------------------------+------------------------------------- Changes (by cactus): * keywords: => PatternSynonyms -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8582#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8582: Record syntax for pattern synonyms -------------------------------------+------------------------------------- Reporter: cactus | Owner: cactus Type: feature request | Status: new Priority: normal | Milestone: Component: Compiler | Version: Resolution: | Keywords: Operating System: Unknown/Multiple | PatternSynonyms Type of failure: None/Unknown | Architecture: Blocked By: 5144 | Unknown/Multiple Related Tickets: | Test Case: | Blocking: | Differential Revisions: -------------------------------------+------------------------------------- Comment (by mpickering): I was also thinking this would be nice and would be interested to implement it before 7.12. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8582#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8582: Record syntax for pattern synonyms -------------------------------------+------------------------------------- Reporter: cactus | Owner: mpickering Type: feature request | Status: new Priority: normal | Milestone: Component: Compiler | Version: Resolution: | Keywords: | PatternSynonyms Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: 5144 | Blocking: Related Tickets: | Differential Revisions: -------------------------------------+------------------------------------- Changes (by mpickering): * owner: cactus => mpickering -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8582#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8582: Record syntax for pattern synonyms -------------------------------------+------------------------------------- Reporter: cactus | Owner: mpickering Type: feature request | Status: new Priority: normal | Milestone: Component: Compiler | Version: Resolution: | Keywords: | PatternSynonyms Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: 5144 | Blocking: Related Tickets: | Differential Revisions: Phab:D1152 -------------------------------------+------------------------------------- Changes (by mpickering): * differential: => Phab:D1152 -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8582#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8582: Record syntax for pattern synonyms -------------------------------------+------------------------------------- Reporter: cactus | Owner: mpickering Type: feature request | Status: new Priority: high | Milestone: 7.12.1 Component: Compiler | Version: Resolution: | Keywords: | PatternSynonyms Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: 5144 | Blocking: Related Tickets: | Differential Revisions: Phab:D1152 -------------------------------------+------------------------------------- Changes (by simonpj): * priority: normal => high * milestone: => 7.12.1 Comment: Matthew says he thinks this'll be ready for 7.12 so I'll milestone it as such. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8582#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8582: Record syntax for pattern synonyms -------------------------------------+------------------------------------- Reporter: cactus | Owner: mpickering Type: feature request | Status: new Priority: high | Milestone: 8.0.1 Component: Compiler | Version: Resolution: | Keywords: | PatternSynonyms Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: 5144 | Blocking: Related Tickets: | Differential Revisions: Phab:D1152 -------------------------------------+------------------------------------- Comment (by goldfire): Some idle thought has spurred on some questions about the design of this feature. See [https://ghc.haskell.org/trac/ghc/wiki/PatternSynonyms#Trickybits a new section on the wiki page]. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8582#comment:9 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8582: Record syntax for pattern synonyms -------------------------------------+------------------------------------- Reporter: cactus | Owner: mpickering Type: feature request | Status: new Priority: high | Milestone: 8.0.1 Component: Compiler | Version: Resolution: | Keywords: | PatternSynonyms Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: 5144 | Blocking: Related Tickets: | Differential Revisions: Phab:D1152 -------------------------------------+------------------------------------- Comment (by mpickering): The first example is a bit tricky although I don't think the results are unexpected. If instead you write {{{ data D = MkD { foo :: Int } pattern Pat = MkD { foo = 6 } baz = (Pat) { foo = 5 } }}} then everything works as expected. Otherwise there is a type error as `Pat` does not have a field `foo`. This is similar to one of the examples I posted on the original discussion thread. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8582#comment:10 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8582: Record syntax for pattern synonyms -------------------------------------+------------------------------------- Reporter: cactus | Owner: mpickering Type: feature request | Status: new Priority: high | Milestone: 8.0.1 Component: Compiler | Version: Resolution: | Keywords: | PatternSynonyms Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: 5144 | Blocking: Related Tickets: | Differential Revisions: Phab:D1152 -------------------------------------+------------------------------------- Comment (by simonpj): I'm sorry but I'm honestly not sure what the specification of the new feature is. The [wiki:PatternSynonyms#Design design subsection] is helpful, but it uses only one example, and I can't tell what is supposed to happen in general. Let's try this. In general, a pattern synonym should behave exactly like its expansion. So given {{{ pattern P x = (x, True) }}} these two functions should behave the same: {{{ f1 (P False) = "yes" f2 (P True) = "no" f2 (False,True) = "yes" -- Replace (P pat) by its expansion f2 (True, True) = "no" }}} (Actually they are not quite the same; see [wiki:PatternSynonyms#DynamicSemantics dynamic semantics subsection]. But close enough for now.) But for your proposal, given {{{ pattern Foo{bar, baz} = (bar, baz) }}} how, exactly should pattern matches on `Foo` expand? I can't tell. Another way to get at this question would be to look at [https://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-580003.1... Section 3.17 of the langauge definition]. What changes, precisely, are required to accommodate pattern synonyms? (It's a deficiency in the current user manual that it does not say.) To give the idea, here is my first stab at extending 3.17.2. Add an extra item to the list, saying * To match a pattern `P p1 .. pn` against a value, where `P` is a pattern synonym defined by `pattern P x1 .. xn = prhs`, * first match the pattern `prhs` against the value, thereby binding `x1`..`xn`. * and then match `p1` agianst `x1`, `p2` against `x2`, and so on in sequence. A similar modification to 3.17.3 would be needed. Now, how would you change those words if your proposal was adopted? Thanks. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8582#comment:11 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8582: Record syntax for pattern synonyms -------------------------------------+------------------------------------- Reporter: cactus | Owner: mpickering Type: feature request | Status: new Priority: high | Milestone: 8.0.1 Component: Compiler | Version: Resolution: | Keywords: | PatternSynonyms Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: 5144 | Blocking: Related Tickets: | Differential Revisions: Phab:D1152 -------------------------------------+------------------------------------- Comment (by mpickering): I think the confusion here is that pattern synonyms is an undescriptive name for the feature. I prefer to think of (bidirectional) pattern synonyms as data constructors which are not (yet) associated with a particular type. It is better then to say that instead of "In general, a pattern synonym should behave exactly like its expansion." that "In general, a pattern synonym should behave exactly like the relevant data constructor". For example, a bidirectional prefix pattern synonym should behave like a prefix data constructor, an infix pattern synonym should behave like an infix data constructor and a record pattern synonym should behave like a record data constructor. When we introduce records the expansion idea falls apart a bit. For normal prefix pattern synonyms there is one way to pattern match and one way to construct (which matches the expansion). With records there are a few ways to pattern match, a few ways to construct and also the possibility to update. This means the syntax has to diverge from the expansion idea as which expansion do we choose? If we define a synonym `P` and datatype `Q` as follows, {{{#!hs pattern MkP :: Int -> Int -> Q pattern MkP{x, y} = MkQ x1 y1 data Q = MkQ { x1 :: Int, y1 :: Int } }}} then we expect `MkP` to behave precisely as `MkQ` modulo field naming. To be clear these situations are as follows. * Construction (`MkP 0 0`) * Construction with record syntax (`MkP { x = 0, y = 1 }`) * Matching (`foo (MkP c l) = ...`) * Matching with normal record syntax (`foo (MkP {x = l, y = c}) = ...`) * Matching with field puns (`foo (MkP {x, y}) = ...`) * Updating with record syntax (`(MkP 0 0) { x = 1 }`) * Using record selectors (`x (MkP 0 0)`) For a unidirectional synonym, we define selectors and the matching part but not updates or construction. Is that clearer? I think the best specification for this feature is in terms of ordinary records as the goal is to get as close as possible to normal record data constructors. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8582#comment:12 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8582: Record syntax for pattern synonyms -------------------------------------+------------------------------------- Reporter: cactus | Owner: mpickering Type: feature request | Status: new Priority: high | Milestone: 8.0.1 Component: Compiler | Version: Resolution: | Keywords: | PatternSynonyms Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: 5144 | Blocking: Related Tickets: | Differential Revisions: Phab:D1152 -------------------------------------+------------------------------------- Comment (by goldfire): Replying to [comment:12 mpickering]:
{{{#!hs
pattern MkP :: Int -> Int -> Q pattern MkP{x, y} = MkQ x1 y1
data Q = MkQ { x1 :: Int, y1 :: Int } }}}
I imagine you meant {{{#!hs pattern MkP{x, y} = MkQ x y }}} Otherwise, I agree with what you've said above. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8582#comment:13 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8582: Record syntax for pattern synonyms -------------------------------------+------------------------------------- Reporter: cactus | Owner: mpickering Type: feature request | Status: new Priority: high | Milestone: 8.0.1 Component: Compiler | Version: Resolution: | Keywords: | PatternSynonyms Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: 5144 | Blocking: Related Tickets: | Differential Rev(s): Phab:D1152 -------------------------------------+------------------------------------- Comment (by simonpj): Matthew, I feel bad about this but I still don't understand the ''specification''. I honestly don't know what it means to say "a pattern synonym should behave like the relevant data constructor". The [wiki:PatternSynonyms#Design wiki page] does not even give a syntax. I think it may be something like this {{{ patsyndecl ::= 'pattern' con var1 .. varn <- pat | 'pattern' con '{' var1 ',' ... ',' varn '}' <- pat | ... more for bidirectional ... }}} where the second line is the new bit. Is that right? Just writing out the syntax would be very helpful. We need semantics as well as syntax. In comment:11 I tried to give some concrete pointers for what a specification might look like. It has to say * What the syntax is * What it means to use such a pattern synonym as a constructor * What it means to match against such a synonym I don't think any of this is very hard to do. But until it is done I don't know what the feature is, so it's hard to review the implementation. On the implementation front, I believe that you are stuck on a particular point. There's a long comment stream on the Phab ticket so I'm not sure what you are stuck on. Can you just identify the sticking point? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8582#comment:14 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8582: Record syntax for pattern synonyms -------------------------------------+------------------------------------- Reporter: cactus | Owner: mpickering Type: feature request | Status: new Priority: high | Milestone: 8.0.1 Component: Compiler | Version: Resolution: | Keywords: | PatternSynonyms Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: 5144 | Blocking: Related Tickets: | Differential Rev(s): Phab:D1152 -------------------------------------+------------------------------------- Comment (by mpickering): Simon, I didn't want to write an explicit specification for this patch because it would amount to copying the specification for records. Which bit did you find confusing in the example I gave? In retrospect, the phrase "relevant data constructor" is confusing. So to explain, by "relevant" I mean an isomorphic (normally defined) data constructor. Does the example not make this any clearer? The problem with the implementation is with the record updates. Pattern synonym builders have required constraints which normal data constructors don't have. When the record update is desugared, it is necessary to provide the dictionaries for these constraints to the builder. My question was, how was I meant to do this. I ended up adding a field to the RecordUpd constructor which carried around the HsWrapper which then applied the dictionaries. More details are to be found in the last comment on the phab ticket. I don't have much time anymore to work on this ticket but I would be very disappointed it if did make it into GHC 8.0 as I started working on it several months ago. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8582#comment:15 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8582: Record syntax for pattern synonyms -------------------------------------+------------------------------------- Reporter: cactus | Owner: mpickering Type: feature request | Status: closed Priority: high | Milestone: 8.0.1 Component: Compiler | Version: Resolution: fixed | Keywords: | PatternSynonyms Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: 5144 | Blocking: Related Tickets: | Differential Rev(s): Phab:D1152 Wiki Page: | -------------------------------------+------------------------------------- Changes (by bgamari): * status: new => closed * resolution: => fixed Comment: Record pattern synonym support has been merged. Moreover, a specification for the implemented syntax can be found on [[PatternSynonyms/RecordPatternSynonyms]]. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8582#comment:16 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8582: Record syntax for pattern synonyms
-------------------------------------+-------------------------------------
Reporter: cactus | Owner: mpickering
Type: feature request | Status: closed
Priority: high | Milestone: 8.0.1
Component: Compiler | Version:
Resolution: fixed | Keywords:
| PatternSynonyms
Operating System: Unknown/Multiple | Architecture:
| Unknown/Multiple
Type of failure: None/Unknown | Test Case:
Blocked By: 5144 | Blocking:
Related Tickets: | Differential Rev(s): Phab:D1152
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by thomie):
commit 2a74a64e8329ab9e0c74bec47198cb492d25affb:
{{{
Author: Matthew Pickering
participants (1)
-
GHC