Reputation: 7757
Consider the following nonsense lambda:
function
| [] -> "Empty list"
| hd::tl -> "Not so empty list"
This works fine. Now I rewrite it as follows:
function
| [] -> "Empty list"
| hd::tl & l -> "Not so empty list"
Again, for nonsense reasons (and I know that I can achieve the same effect by using as
instead of &
, but this all has to do with a code-golf problem that's not pertinent to this question). Now the F# compiler tells me:
warning FS0025: Incomplete pattern matches on this expression. For example, the value '[]' may indicate a case not covered by the pattern(s).
This doesn't make any sense - I am explicitly handling the case of []
in the first rule. I don't see what changed from the first function to the second with respect to []
; neither function's second rule would have matched it yet only the second function gives the warning. All I did was add an additional pattern that matches anything.
Of course, invoking the second function with an empty list does succeed.
Is there a valid reason why this warning occurred, or does the F# pattern validation simply have some quirks? I could see having some cases like this when more advanced patterns are employed, but this seems like a pretty basic one. Even if the problem can't be solved generally, it seems like this type of case would be common enough to merit special handling in the compiler.
Upvotes: 6
Views: 1043
Reputation: 243051
I guess you found another case (aside from when
clauses and partial active patterns) where the compiler's decision procedure is not powerful enough. (That's why the warning message says may indicate :-)).
If you wanted to get the same functionality without warnings, then you could use a complete active pattern like this (but in reality, for lists, I would probably just go with _
for the empty list case as @pad suggests):
let (|Empty|NonEmpty|) l =
match l with [] -> Empty | x::xs -> NonEmpty(x, xs, l)
let foo = function
| Empty -> 0
| NonEmpty(x, xs, l) -> 1
Upvotes: 4
Reputation: 41290
I think F# compiler is being practical in this case.
In the end, the second rule can be expressed as a constraint on input list xs
:
xs = hd :: tl && xs = l
F# compiler doesn't seem to explore &&
constraints. This is reasonable because constraints can be arbitrarily complex and the use of &
is quite rare.
We have a similar problem with partial active patterns:
let (|Empty|_|) = function
| [] -> Some()
| _ -> None
let (|NonEmpty|_|) = function
| _ :: _ -> Some()
| _ -> None
// warning FS0025
let f = function
| Empty -> "Empty list"
| NonEmpty -> "Not so empty list"
To fix this issue, you can:
as
instead of &
, which is more appropriate since l
is just a binding.Add a wildcard pattern to the end to eliminate the warning. I usually write
let f =
function
| hd::tl & l -> "Not so empty list"
| _ -> "Empty list"
Suppress the warning using nowarn "25"
.
Upvotes: 6