Constructor synonyms, signatures on pattern synonym constructors

I’m shepherding this two intertwined proposals, the Github discussions are located at: - https://github.com/ghc-proposals/ghc-proposals/pull/41 - https://github.com/ghc-proposals/ghc-proposals/pull/42 The rendered proposals are located at time of review at: - https://github.com/treeowl/ghc-proposals/blob/680d909a07b10b6a37a64adf174ee8... - https://github.com/treeowl/ghc-proposals/blob/559df2865db8e4427b1f24d3100e59... Very briefly, Proposal #41 is constructor synonyms. This would allow users to define variables with capitalized names and operators that begin with colons. They are meant to complement pattern synonyms. This example from the rendered proposal captures the idea and complementarity well I think: pattern NF :: a -> NF a pattern NF a <- UnsafeNF a constructor NF :: NFData a => a -> NF a constructor NF a = a `deepseq` UnsafeNF a pattern Zero :: (Eq a, Num a) => a pattern Zero <- ((== 0) -> True) constructor Zero :: Num a => a constructor Zero = 0 Proposal #42 would add type signatures for bidirectional pattern synonym constructor functions. Currently we can write this: pattern Zero :: (Num a, Eq a) => a pattern Zero <- ((== 0) -> True) where Zero = 0 Per Feuer:
The trouble in this case is that the Eq constraint from the pattern "infects" the constructor. So if I have a number type I can't test for equality, I can't use Zero to construct it.
It would permit writing things like this instead: pattern Zero :: (Eq a, Num a) => a pattern Zero <- ((== 0) -> True) where Zero :: Num a => a -- optional Zero = 0 This would prevent the pattern’s Eq constraint from “infecting” using Zero as a constructor, which doesn’t actually need Eq. — My thoughts follow — I think Richard’s right about how we’ll need to handle compatibility. I agree that the current warnings policy is a bit restrictive but it’s not worth getting people riled up over it. I agree with Simon's comment on #42. I think we need to take seriously whether or not this proposal compromises the use-case of the naïve user consuming a library API that uses pattern constructors. Partly why I feel this is important is that as much debate as it draws, Haskell users consuming a lens-based API are able to cargo cult and move on with what they’re doing. I think pattern constructors should be held to a higher usability standard than lens due to looking like data constructors and being baked into the implementation. This seems to clear up a limitation in expressiveness with few downsides as long as we avoid using holes and respect the community’s desires on backwards compatibility. Avoiding holes should make implementation easier and have fewer unpredictable behaviors down the road as well. — My recommendation for the proposal — My recommendation is that we accept both proposals. My reservation would be that it shouldn't have serious downsides for the existing users of pattern synonyms, be they authors or consumers. Cheers, Chris

Hi, Am Dienstag, den 21.03.2017, 00:55 -0500 schrieb Christopher Allen:
Proposal #41 is constructor synonyms. This would allow users to define variables with capitalized names and operators that begin with colons. They are meant to complement pattern synonyms. This example from the rendered proposal captures the idea and complementarity well I think:
pattern NF :: a -> NF a pattern NF a <- UnsafeNF a
constructor NF :: NFData a => a -> NF a constructor NF a = a `deepseq` UnsafeNF a
pattern Zero :: (Eq a, Num a) => a pattern Zero <- ((== 0) -> True)
constructor Zero :: Num a => a constructor Zero = 0
it is worth pointing out that under this proposal, constructor FireMissles :: IO () constructor FireMissles = fireMissles (without a pattern) is also valid. In other words: The capitalization of an identifier will no longer be of significance. This makes me dislike the proposal. I guess I would be fine with it if "constructor" were only ever used together with "pattern". In that case, it would be simply a different syntax for the other proposal.
Proposal #42 would add type signatures for bidirectional pattern synonym constructor functions.
pattern Zero :: (Eq a, Num a) => a pattern Zero <- ((== 0) -> True) where Zero :: Num a => a -- optional Zero = 0
This would prevent the pattern’s Eq constraint from “infecting” using Zero as a constructor, which doesn’t actually need Eq.
In principle in favor of this. I am less concerned about what :i would show. It could simply use comments like in the following to explain directionality and possibly different signatures. :i Just -- real constructor Just :: a -> Maybe a :i HashOf -- unidirectional Hash :: Hashable a => Hash -> a -- pattern matching only :i Snoc -- bidirectional, same types Snoc :: [a] -> a -> [a] :i Zero -- bidirectional, diffrent types, as above Zero :: (Eq a, Num a) => a -- when matching Zero :: Num a => a -- when constructing The proposal does not address if the signatures of the constructor and the signature of the pattern have to be in any way related. Possible design choices are: * May not differ in anything but the constraints. * Must have the same return type. * Must have the same outer type constructor in their return type. * No relation. This ought to be clarified. Greetings, Joachim -- Joachim Breitner mail@joachim-breitner.de http://www.joachim-breitner.de/

Hi,
I'm in a slightly difficult situation here since I quite dislike the
current pattern synonyms extension. I'll try nonetheless.
On Tue, Mar 21, 2017 at 1:43 PM, Joachim Breitner
Hi,
Am Dienstag, den 21.03.2017, 00:55 -0500 schrieb Christopher Allen:
Proposal #41 is constructor synonyms. This would allow users to [...]
it is worth pointing out that under this proposal,
constructor FireMissles :: IO () constructor FireMissles = fireMissles
(without a pattern) is also valid. In other words: The capitalization of an identifier will no longer be of significance.
This makes me dislike the proposal.
I completely agree. In fact, this proposal is basically about allowing value variable names to start with an upper case letter so if we want to go that way then I'm not sure why the keyword 'constructor' is necessary at all. I would much prefer not to go that way, though, so I'm against #41.
Proposal #42 would add type signatures for bidirectional pattern synonym constructor functions. [...]
This seems sensible provided there is a strong relation between the types of the constructor and the pattern.
The proposal does not address if the signatures of the constructor and the signature of the pattern have to be in any way related. Possible design choices are: * May not differ in anything but the constraints. * Must have the same return type. * Must have the same outer type constructor in their return type. * No relation. This ought to be clarified.
This is a very good point. I'd be in favour of this proposal under the "May not differ in anything but the constraints" policy and against it under any of the other three. A looser relationship between the constructor function and the pattern makes code significantly harder to read and the proposal doesn't include any justification for such a looser relationship so I would go with the strongest requirement possible. Thanks, Roman

On 21 March 2017 at 23:26, Roman Leshchinskiy
Hi,
I'm in a slightly difficult situation here since I quite dislike the current pattern synonyms extension. I'll try nonetheless.
On Tue, Mar 21, 2017 at 1:43 PM, Joachim Breitner
wrote: Hi,
Am Dienstag, den 21.03.2017, 00:55 -0500 schrieb Christopher Allen:
Proposal #41 is constructor synonyms. This would allow users to [...]
it is worth pointing out that under this proposal,
constructor FireMissles :: IO () constructor FireMissles = fireMissles
(without a pattern) is also valid. In other words: The capitalization of an identifier will no longer be of significance.
This makes me dislike the proposal.
I completely agree. In fact, this proposal is basically about allowing value variable names to start with an upper case letter so if we want to go that way then I'm not sure why the keyword 'constructor' is necessary at all. I would much prefer not to go that way, though, so I'm against #41.
Yes, I think I agree with this too. The point of pattern synonyms is to let you define something that to the importer of a module looks exactly like a data constructor, while allowing the author of the module to change its implementation. It fills in a missing opportunity for abstraction in the language. But constructor synonyms go much further than this, allowing you to define something that looks like a data constructor but doesn't behave anything like one. It drops the requirement that the constructor be expressible as a pattern. If you want to do this, define a function! Why not solve the original problem by allowing a separate type signature on the constructor in the pattern synonym? There's already an example of this in the proposal: pattern Zero :: (Eq a, Num a) => a pattern Zero <- ((== 0) -> True) where Zero :: Num a => a Zero = 0 (the proposal has the signature on Zero slightly wrong, I think). This seems like it would address the problem but without also overly generalising what a conid can represent, and avoids the issues with import/export. Digressing a bit, I wish it were possible to write the pattern above as pattern Zero :: (Eq a, Num a) => a pattern Zero <- x | x == 0 where Zero :: Num a => a Zero = 0 because I think ViewPatterns were a mistake. But that's a proposal for another day :) Cheers Simon
Proposal #42 would add type signatures for bidirectional pattern
synonym constructor functions. [...]
This seems sensible provided there is a strong relation between the types of the constructor and the pattern.
The proposal does not address if the signatures of the constructor and the signature of the pattern have to be in any way related. Possible design choices are: * May not differ in anything but the constraints. * Must have the same return type. * Must have the same outer type constructor in their return type. * No relation. This ought to be clarified.
This is a very good point. I'd be in favour of this proposal under the "May not differ in anything but the constraints" policy and against it under any of the other three. A looser relationship between the constructor function and the pattern makes code significantly harder to read and the proposal doesn't include any justification for such a looser relationship so I would go with the strongest requirement possible.
Thanks,
Roman _______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee

Digressing a bit, I wish it were possible to write the pattern above as
I agree! See: https://ghc.haskell.org/trac/ghc/wiki/ViewPatternsAlternative
Maybe we should work that up into a new GHC proposal.
Simon
From: ghc-steering-committee [mailto:ghc-steering-committee-bounces@haskell.org] On Behalf Of Simon Marlow
Sent: 23 March 2017 10:01
To: Roman Leshchinskiy
Hi,
Am Dienstag, den 21.03.2017, 00:55 -0500 schrieb Christopher Allen:
Proposal #41 is constructor synonyms. This would allow users to [...]
it is worth pointing out that under this proposal,
constructor FireMissles :: IO () constructor FireMissles = fireMissles
(without a pattern) is also valid. In other words: The capitalization of an identifier will no longer be of significance.
This makes me dislike the proposal.
I completely agree. In fact, this proposal is basically about allowing value variable names to start with an upper case letter so if we want to go that way then I'm not sure why the keyword 'constructor' is necessary at all. I would much prefer not to go that way, though, so I'm against #41. Yes, I think I agree with this too. The point of pattern synonyms is to let you define something that to the importer of a module looks exactly like a data constructor, while allowing the author of the module to change its implementation. It fills in a missing opportunity for abstraction in the language. But constructor synonyms go much further than this, allowing you to define something that looks like a data constructor but doesn't behave anything like one. It drops the requirement that the constructor be expressible as a pattern. If you want to do this, define a function! Why not solve the original problem by allowing a separate type signature on the constructor in the pattern synonym? There's already an example of this in the proposal: pattern Zero :: (Eq a, Num a) => a pattern Zero <- ((== 0) -> True) where Zero :: Num a => a Zero = 0 (the proposal has the signature on Zero slightly wrong, I think). This seems like it would address the problem but without also overly generalising what a conid can represent, and avoids the issues with import/export. Digressing a bit, I wish it were possible to write the pattern above as pattern Zero :: (Eq a, Num a) => a pattern Zero <- x | x == 0 where Zero :: Num a => a Zero = 0 because I think ViewPatterns were a mistake. But that's a proposal for another day :) Cheers Simon
Proposal #42 would add type signatures for bidirectional pattern synonym constructor functions. [...]
This seems sensible provided there is a strong relation between the types of the constructor and the pattern.
The proposal does not address if the signatures of the constructor and the signature of the pattern have to be in any way related. Possible design choices are: * May not differ in anything but the constraints. * Must have the same return type. * Must have the same outer type constructor in their return type. * No relation. This ought to be clarified.
This is a very good point. I'd be in favour of this proposal under the "May not differ in anything but the constraints" policy and against it under any of the other three. A looser relationship between the constructor function and the pattern makes code significantly harder to read and the proposal doesn't include any justification for such a looser relationship so I would go with the strongest requirement possible. Thanks, Roman _______________________________________________ ghc-steering-committee mailing list ghc-steering-committee@haskell.orgmailto:ghc-steering-committee@haskell.org https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee

Some thoughts · To me it's clear that we should abandon #41 in favour of #42. Indeed the author did so himself, but then re-opened it saying only "@kosmikus thinks this should be reopened". I could elaborate, but see the discussion on #41. I think it’s pretty much a consensus. · For #42, I’m mildly in favour, as I said on the thread. (But no holes please!) · I agree with Roman that that type of the constructor should be the same as that of the pattern, constrains aside. We can always loosen later if there is well-supported evidence that doing so would be good. Simon | -----Original Message----- | From: ghc-steering-committee [mailto:ghc-steering-committee- | bounces@haskell.org] On Behalf Of Christopher Allen | Sent: 21 March 2017 05:55 | To: ghc-steering-committee@haskell.org | Subject: [ghc-steering-committee] Constructor synonyms, signatures on | pattern synonym constructors | | I’m shepherding this two intertwined proposals, the Github discussions | are located at: | | - https://github.com/ghc-proposals/ghc-proposals/pull/41 | - https://github.com/ghc-proposals/ghc-proposals/pull/42 | | The rendered proposals are located at time of review at: | | - https://github.com/treeowl/ghc-https://github.com/treeowl/ghc-proposals/blob/680d909a07b10b6a37a64adf174ee8... | proposals/blob/680d909a07b10b6a37a64adf174ee845783dc2a4/proposals/0000https://github.com/treeowl/ghc-proposals/blob/680d909a07b10b6a37a64adf174ee8... | -constructor-synonyms.rsthttps://github.com/treeowl/ghc-proposals/blob/680d909a07b10b6a37a64adf174ee8... | - https://github.com/treeowl/ghc-https://github.com/treeowl/ghc-proposals/blob/559df2865db8e4427b1f24d3100e59... | proposals/blob/559df2865db8e4427b1f24d3100e59d61cb60e54/proposals/0000https://github.com/treeowl/ghc-proposals/blob/559df2865db8e4427b1f24d3100e59... | -bidir-constr-sigs.rsthttps://github.com/treeowl/ghc-proposals/blob/559df2865db8e4427b1f24d3100e59... | | Very briefly, | | Proposal #41 is constructor synonyms. This would allow users to define | variables with capitalized names and operators that begin with colons. | They are meant to complement pattern synonyms. This example from the | rendered proposal captures the idea and complementarity well I think: | | | pattern NF :: a -> NF a | pattern NF a <- UnsafeNF a | | constructor NF :: NFData a => a -> NF a | constructor NF a = a `deepseq` UnsafeNF a | | pattern Zero :: (Eq a, Num a) => a | pattern Zero <- ((== 0) -> True) | | constructor Zero :: Num a => a | constructor Zero = 0 | | Proposal #42 would add type signatures for bidirectional pattern | synonym constructor functions. Currently we can write this: | | pattern Zero :: (Num a, Eq a) => a | pattern Zero <- ((== 0) -> True) | where | Zero = 0 | | Per Feuer: | | >The trouble in this case is that the Eq constraint from the pattern | "infects" the constructor. So if I have a number type I can't test for | equality, I can't use Zero to construct it. | | It would permit writing things like this instead: | | pattern Zero :: (Eq a, Num a) => a | pattern Zero <- ((== 0) -> True) where | Zero :: Num a => a -- optional | Zero = 0 | | This would prevent the pattern’s Eq constraint from “infecting” using | Zero as a constructor, which doesn’t actually need Eq. | | | — My thoughts follow — | | I think Richard’s right about how we’ll need to handle compatibility. | I agree that the current warnings policy is a bit restrictive but it’s | not worth getting people riled up over it. | | I agree with Simon's comment on #42. I think we need to take seriously | whether or not this proposal compromises the use-case of the naïve | user consuming a library API that uses pattern constructors. Partly | why I feel this is important is that as much debate as it draws, | Haskell users consuming a lens-based API are able to cargo cult and | move on with what they’re doing. I think pattern constructors should | be held to a higher usability standard than lens due to looking like | data constructors and being baked into the implementation. | | This seems to clear up a limitation in expressiveness with few | downsides as long as we avoid using holes and respect the community’s | desires on backwards compatibility. Avoiding holes should make | implementation easier and have fewer unpredictable behaviors down the | road as well. | | | — My recommendation for the proposal — | | My recommendation is that we accept both proposals. My reservation | would be that it shouldn't have serious downsides for the existing | users of pattern synonyms, be they authors or consumers. | | | Cheers, | Chris | _______________________________________________ | ghc-steering-committee mailing list | ghc-steering-committee@haskell.orgmailto:ghc-steering-committee@haskell.org | https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee | committeehttps://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee
participants (5)
-
Christopher Allen
-
Joachim Breitner
-
Roman Leshchinskiy
-
Simon Marlow
-
Simon Peyton Jones