incomplete-uni-patterns

Hello, The recent GHC added incomplete-uni-patterns to the -Wall option. So, we have a waning with the following code: let [addr,port] = args To avoid this, I changed the code to: let addr = head args port = head $ tail args In my opinion, this seems Lisp rather than Haskell. Also, I need to avoid: let Just val = mval Rahter, I use: let val = fromJust mval This is annoying to me. How do you get along with incomplete-uni-patterns? I would like to know the best current practice. --Kazu

Does this suppress the warning?: let ~[addr,port] = args and let ~(Just val) = mval Jeff
On Jan 25, 2023, at 4:05 PM, Kazu Yamamoto (山本和彦) via Haskell-Cafe
wrote: Hello,
The recent GHC added incomplete-uni-patterns to the -Wall option. So, we have a waning with the following code:
let [addr,port] = args
To avoid this, I changed the code to:
let addr = head args port = head $ tail args
In my opinion, this seems Lisp rather than Haskell.
Also, I need to avoid:
let Just val = mval
Rahter, I use:
let val = fromJust mval
This is annoying to me.
How do you get along with incomplete-uni-patterns? I would like to know the best current practice.
--Kazu
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

On Wed, Jan 25, 2023 at 04:29:08PM -0800, Jeff Clites via Haskell-Cafe wrote:
Does this suppress the warning?:
let ~[addr,port] = args
and
let ~(Just val) = mval
I would expect that, and indeed: $ ghci -Wall GHCi, version 9.4.4: https://www.haskell.org/ghc/ :? for help λ> let ~[a,b] = [1,2] <interactive>:1:5: warning: [-Wincomplete-uni-patterns] Pattern match(es) are non-exhaustive In a pattern binding: Patterns of type ‘[a]’ not matched: [] [_] (_:_:_:_) λ> -- Viktor.

On Thu, 26 Jan 2023, Kazu Yamamoto (山本和彦) via Haskell-Cafe wrote:
The recent GHC added incomplete-uni-patterns to the -Wall option. So, we have a waning with the following code:
let [addr,port] = args
To avoid this, I changed the code to:
let addr = head args port = head $ tail args
Both are partial and should be avoided. I have a nestable NonEmpty that lets you use NonEmpty (NonEmpty []) for a list of at least two elements: https://hackage.haskell.org/package/non-empty-0.3.3/docs/Data-NonEmpty.html
In my opinion, this seems Lisp rather than Haskell.
Also, I need to avoid:
let Just val = mval
Rahter, I use:
let val = fromJust mval
This is annoying to me.
If you are sure that the Maybe is always Just, why use Maybe in the first place?

If you are sure that the Maybe is always Just, why use Maybe in the first place?
I'm not sure this is a good example but suppose you have a variable which is shared by clients and servers. For clients, this variable is not necessary. So, to set a value, "Nothing" is used.
From the server code, the value is always "Just x" (by configuration or something).
Even if this example is not appearing to you, there are a lot of situations of this kind in practical code. --Kazu

On Thu, 26 Jan 2023, Kazu Yamamoto (山本和彦) via Haskell-Cafe wrote:
Even if this example is not appearing to you, there are a lot of situations of this kind in practical code.
I know. Each of this is an occasion to think about more appropriate types, such that only valid values can be represented.

Another possibility is to write something like: main = do [addr, port] <- pure args ... This is desugared in terms of `fail` rather than `error`, so it will also do the right thing in the `Maybe` monad. Though of course this only works in do-notation. -- Teo On Thu, 26 Jan 2023, 09:35 Henning Thielemann, < lemming@henning-thielemann.de> wrote:
On Thu, 26 Jan 2023, Kazu Yamamoto (山本和彦) via Haskell-Cafe wrote:
Even if this example is not appearing to you, there are a lot of situations of this kind in practical code.
I know. Each of this is an occasion to think about more appropriate types, such that only valid values can be represented._______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

I feel I should raise the naive question, what if args is wrong?
[addr,50,50] when a user mistyped port 5050 as 50 50
[addr] when a user was "sure" somebody else's code would insert 5050 as the default
What would you like your code to do in those two cases?
I have been using Haskell seriously for only about two years, so I am still idealistic about it. On the other hand, I worked in the software industry for about ten years, and back then my boss would have chewed me out if my Java code had crashed on the input of 50 50. On Wednesday, January 25, 2023 at 07:06:30 PM EST, Kazu Yamamoto (山本和彦) via Haskell-Cafe

On Thu, Jan 26, 2023 at 12:21:31PM +0900, Kazu Yamamoto (山本和彦) via Haskell-Cafe wrote:
I feel I should raise the naive question, what if args is wrong?
The length of "args" have been checked in advance. I'm sure that the length is 2.
Then, at the point you check the args, put them in a pair?

On Thu, 26 Jan 2023, Kazu Yamamoto (山本和彦) via Haskell-Cafe wrote:
I feel I should raise the naive question, what if args is wrong?
The length of "args" have been checked in advance. I'm sure that the length is 2.
If that is sure, then let the length check return a list type that contains exactly two arguments. With my non-empty package I would e.g. use NonEmpty (NonEmpty Empty).

On Thu, Jan 26, 2023 at 09:05:40AM +0900, Kazu Yamamoto (山本和彦) via Haskell-Cafe wrote:
Hello,
The recent GHC added incomplete-uni-patterns to the -Wall option. So, we have a waning with the following code:
let [addr,port] = args
To avoid this, I changed the code to:
let addr = head args port = head $ tail args
The univeral option type is Maybe, so you leverage that: maybePair :: [a] -> Maybe (a, a) maybePair [a, b] = Just (a, b) maybePair _ = Nothing knownPair :: [a] -> (a, a) knownPair = fromJust . maybePair and then anywhere you need to only match a 2-element list: let (a, b) = knownPair args Or just: {-# OPTIONS_GHC -Wall -Wno-incomplete-uni-patterns #-} let [a, b] knownPair args Perhaps mildly inconvenient at times, but I am inlined to think that overall better than never reporting potential problem patterns. -- Viktor.

It seems to me that instead of working around this, we should add a pragma to suppress the warning at the pattern site. Maybe something like let {-# PARTIAL_MATCH #-} Just a = blah blah That way GHC can see that you noticed the partial match and that you're okay with it. On Wed, Jan 25, 2023, 7:06 PM Kazu Yamamoto (山本和彦) via Haskell-Cafe < haskell-cafe@haskell.org> wrote:
Hello,
The recent GHC added incomplete-uni-patterns to the -Wall option. So, we have a waning with the following code:
let [addr,port] = args
To avoid this, I changed the code to:
let addr = head args port = head $ tail args
In my opinion, this seems Lisp rather than Haskell.
Also, I need to avoid:
let Just val = mval
Rahter, I use:
let val = fromJust mval
This is annoying to me.
How do you get along with incomplete-uni-patterns? I would like to know the best current practice.
--Kazu
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Hi David,
It seems to me that instead of working around this, we should add a pragma to suppress the warning at the pattern site. Maybe something like
let {-# PARTIAL_MATCH #-} Just a = blah blah
That way GHC can see that you noticed the partial match and that you're okay with it.
This sounds lovely to me! --Kazu

One can also put this at the top:
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
On Thursday, January 26, 2023 at 12:24:49 AM EST, Kazu Yamamoto (山本和彦) via Haskell-Cafe
It seems to me that instead of working around this, we should add a pragma to suppress the warning at the pattern site. Maybe something like
let {-# PARTIAL_MATCH #-} Just a = blah blah
That way GHC can see that you noticed the partial match and that you're okay with it.
This sounds lovely to me! --Kazu _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
I feel like that's just avoiding facing the problem. It makes sense though, if you know 100% that there really, really is no other case. But as previous repliers have said, that's probably not a case for partials. If it's both known and partial, you're probably using the wrong datastructure for it. There's a reason many Prelude replacements don't include partial functions, and there's generally a better solution for it in them. And even if you're using base Prelude (which I am 99% of the time), things are only Maybe if they come from somewhere where they possibly could be. So, taking (!?) as an example, if you've statically set a list to contain a value and want it out, and want to avoid using partial functions like (!!) then perhaps static lists were not a good use case for you, is what I think people are getting at.
what if args is wrong?
Another solution I use a lot is to match on lists, e.g.: doSomethingWithListOfParameters :: [Text] -> IO () doSomethingWithListOfParameters xs = \case [] -> someActionUsingNoParameters [a] -> someActionUsingOneParameter [a, b] -> someActionUsingTwoParameters _ -> fail "don't know that one, sorry" I have adapted a lot of my code to use these uni patterns rather than avoiding them, as most of the time when this happens, it's not an impossible case for someone to pick the function up somewhere else and call it in the "wrong" way, and I handle it.

There are occasional situations where the data structure is right but the
limitations of Haskell's type system prevent us from proving totality. I've
only ever written a couple I'm proud of:
1. Data.Biapplicative.traverseBiaWith
2. Data.Sequence.zipWith and Data.Sequence.chunksOf
traverseBiaWith seems to need an "impossible" case to achieve the right
semantics for lazy biapplicatives and infinite structures. Code shared by
zipWith and chunksOf uses one (relying on the tree annotation invariant) to
compute the result incrementally and (therefore) more efficiently.
On Thu, Jan 26, 2023, 8:34 AM Dan Dart
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
I feel like that's just avoiding facing the problem. It makes sense though, if you know 100% that there really, really is no other case. But as previous repliers have said, that's probably not a case for partials. If it's both known and partial, you're probably using the wrong datastructure for it. There's a reason many Prelude replacements don't include partial functions, and there's generally a better solution for it in them. And even if you're using base Prelude (which I am 99% of the time), things are only Maybe if they come from somewhere where they possibly could be.
So, taking (!?) as an example, if you've statically set a list to contain a value and want it out, and want to avoid using partial functions like (!!) then perhaps static lists were not a good use case for you, is what I think people are getting at.
what if args is wrong?
Another solution I use a lot is to match on lists, e.g.:
doSomethingWithListOfParameters :: [Text] -> IO () doSomethingWithListOfParameters xs = \case [] -> someActionUsingNoParameters [a] -> someActionUsingOneParameter [a, b] -> someActionUsingTwoParameters _ -> fail "don't know that one, sorry"
I have adapted a lot of my code to use these uni patterns rather than avoiding them, as most of the time when this happens, it's not an impossible case for someone to pick the function up somewhere else and call it in the "wrong" way, and I handle it. _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

There's a broader class of problems where achieving totality by restricting
the type is possible, but the cost-benefit trade-off of forcing everything
into the type level comes out in the wrong direction. I ran into an
example in
https://medium.com/@cdsmithus/pair-programming-with-chatgpt-haskell-1c4490b7...
(scroll to the end and see final code for Part IV, and the
toMatrixVectorForm function), where in the general case I needed polynomial
arithmetic, but in certain specific cases (where either one of the two
players of the game adopts a pure strategy), I knew that the result would
always be a linear expression. It would definitely be possible to annotate
the polynomial type with a maximum degree, define higher-kinded arithmetic
operations that would correctly propagate that across addition and
multiplication, and use a bounded-length list type for variables in a term,
all to avoid that one error case in pattern matching. However, it would
have been a significant distraction from the problem being solved.
On Thu, Jan 26, 2023 at 10:46 AM David Feuer
There are occasional situations where the data structure is right but the limitations of Haskell's type system prevent us from proving totality. I've only ever written a couple I'm proud of:
1. Data.Biapplicative.traverseBiaWith 2. Data.Sequence.zipWith and Data.Sequence.chunksOf
traverseBiaWith seems to need an "impossible" case to achieve the right semantics for lazy biapplicatives and infinite structures. Code shared by zipWith and chunksOf uses one (relying on the tree annotation invariant) to compute the result incrementally and (therefore) more efficiently.
On Thu, Jan 26, 2023, 8:34 AM Dan Dart
wrote: {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
I feel like that's just avoiding facing the problem. It makes sense though, if you know 100% that there really, really is no other case. But as previous repliers have said, that's probably not a case for partials. If it's both known and partial, you're probably using the wrong datastructure for it. There's a reason many Prelude replacements don't include partial functions, and there's generally a better solution for it in them. And even if you're using base Prelude (which I am 99% of the time), things are only Maybe if they come from somewhere where they possibly could be.
So, taking (!?) as an example, if you've statically set a list to contain a value and want it out, and want to avoid using partial functions like (!!) then perhaps static lists were not a good use case for you, is what I think people are getting at.
what if args is wrong?
Another solution I use a lot is to match on lists, e.g.:
doSomethingWithListOfParameters :: [Text] -> IO () doSomethingWithListOfParameters xs = \case [] -> someActionUsingNoParameters [a] -> someActionUsingOneParameter [a, b] -> someActionUsingTwoParameters _ -> fail "don't know that one, sorry"
I have adapted a lot of my code to use these uni patterns rather than avoiding them, as most of the time when this happens, it's not an impossible case for someone to pick the function up somewhere else and call it in the "wrong" way, and I handle it. _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Just a miscellaneous Haskell user, but that also sounds good to me. I definitely support having a way to tell the compiler at the most specific level possible (per line, in this case) that the author is intentionally doing this and not to warn about it. I wrote in scala for years and was always unhappy that for a very long time the designers refused to support [1] ( a scala version of Java's @SuppressWarnings annotation. The suggested hack for about a decade was to use a compiler plugin. ------------------------------------------------------------------------ Unrelated/on the importance of warning about the right things: Thinking about this made me remember that C's switch fall-through-by-default behavior is so bad that you need to tell the compiler you actually want to do that. [2] [3] [1] https://stackoverflow.com/questions/3506370/is-there-an-equivalent-to-suppre... [2] https://learn.microsoft.com/en-us/cpp/code-quality/c26819?view=msvc-170 [3] https://en.cppreference.com/w/c/language/attributes/fallthrough On 1/25/23 21:24, Kazu Yamamoto (山本和彦) via Haskell-Cafe wrote:
Hi David,
It seems to me that instead of working around this, we should add a pragma to suppress the warning at the pattern site. Maybe something like
let {-# PARTIAL_MATCH #-} Just a = blah blah
That way GHC can see that you noticed the partial match and that you're okay with it. This sounds lovely to me!
--Kazu
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

On Thu, 26 Jan 2023, Thomas Jakway wrote:
I definitely support having a way to tell the compiler at the most specific level possible (per line, in this case) that the author is intentionally doing this and not to warn about it.
I think that an explicit 'error' for unhandled cases perfectly serves that purpose.

On Fri, Jan 27, 2023 at 10:24:27AM +0100, Henning Thielemann wrote:
On Thu, 26 Jan 2023, Thomas Jakway wrote:
I definitely support having a way to tell the compiler at the most specific level possible (per line, in this case) that the author is intentionally doing this and not to warn about it.
I think that an explicit 'error' for unhandled cases perfectly serves that purpose.
Big +1 to everything Henning is saying in this discussion.

I suppose it's safer than having a "I know what I'm doing, the list is complete really" pragma?

--living-dangerously
On Fri, Jan 27, 2023, 3:31 AM Dan Dart
I suppose it's safer than having a "I know what I'm doing, the list is complete really" pragma? _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

In violation of the usual conventions, GHC does not implement --no-living-dangerously because the results cannot be guaranteed.
On Friday, January 27, 2023 at 04:15:33 PM EST, Thomas Jakway

That was my thinking with using an explicit lazy pattern match indication: let ~(Just a) = … It seems to me that this shouldn’t warn (though apparently it does), since it’s overly opting in to a non-exhaustive match. Jeff
On Jan 25, 2023, at 9:08 PM, David Feuer
wrote: It seems to me that instead of working around this, we should add a pragma to suppress the warning at the pattern site. Maybe something like
let {-# PARTIAL_MATCH #-} Just a = blah blah
That way GHC can see that you noticed the partial match and that you're okay with it.
On Wed, Jan 25, 2023, 7:06 PM Kazu Yamamoto (山本和彦) via Haskell-Cafe
wrote: Hello, The recent GHC added incomplete-uni-patterns to the -Wall option. So, we have a waning with the following code:
let [addr,port] = args
To avoid this, I changed the code to:
let addr = head args port = head $ tail args
In my opinion, this seems Lisp rather than Haskell.
Also, I need to avoid:
let Just val = mval
Rahter, I use:
let val = fromJust mval
This is annoying to me.
How do you get along with incomplete-uni-patterns? I would like to know the best current practice.
--Kazu
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

A lazy pattern match isn't opting into partiality. Lazy patterns are often things like tuples. On Thu, Jan 26, 2023, 12:49 AM Jeff Clites via Haskell-Cafe < haskell-cafe@haskell.org> wrote:
That was my thinking with using an explicit lazy pattern match indication:
let ~(Just a) = …
It seems to me that this shouldn’t warn (though apparently it does), since it’s overly opting in to a non-exhaustive match.
Jeff
On Jan 25, 2023, at 9:08 PM, David Feuer
wrote: It seems to me that instead of working around this, we should add a pragma to suppress the warning at the pattern site. Maybe something like
let {-# PARTIAL_MATCH #-} Just a = blah blah
That way GHC can see that you noticed the partial match and that you're okay with it.
On Wed, Jan 25, 2023, 7:06 PM Kazu Yamamoto (山本和彦) via Haskell-Cafe < haskell-cafe@haskell.org> wrote:
Hello,
The recent GHC added incomplete-uni-patterns to the -Wall option. So, we have a waning with the following code:
let [addr,port] = args
To avoid this, I changed the code to:
let addr = head args port = head $ tail args
In my opinion, this seems Lisp rather than Haskell.
Also, I need to avoid:
let Just val = mval
Rahter, I use:
let val = fromJust mval
This is annoying to me.
How do you get along with incomplete-uni-patterns? I would like to know the best current practice.
--Kazu
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

On Thu, 26 Jan 2023, David Feuer wrote:
It seems to me that instead of working around this, we should add a pragma to suppress the warning at the pattern site. Maybe something like let {-# PARTIAL_MATCH #-} Just a = blah blah
That way GHC can see that you noticed the partial match and that you're okay with it.
Not necessary. You can just do: case mayb of Just a -> do real things Nothing -> error "problem arised"
participants (12)
-
Chris Smith
-
Dan Dart
-
David Feuer
-
Henning Thielemann
-
Jeff Clites
-
Kazu Yamamoto
-
Mark McConnell
-
Teofil Camarasu
-
Thomas Jakway
-
Tom Ellis
-
Travis Cardwell
-
Viktor Dukhovni