F # pattern matching fuzzy
Consider the following lambda nonsense:
function | [] -> "Empty list" | hd::tl -> "Not so empty list" It works great. Now I rewrite it as follows:
function | [] -> "Empty list" | hd::tl & l -> "Not so empty list" Again, for pointless reasons (and I know that I can achieve the same effect using as instead of & , but all this is due to a code golf problem that is not relevant to this issue). Now the F # compiler tells me:
warning FS0025: incompatible patterns with this expression. For example, the value "[]" may indicate a case that is not covered by the pattern (s).
This makes no sense - I directly handle case [] in the first rule. I do not see what has changed from the first function to the second with respect to [] ; neither the second second rule will correspond to it, but only the second function gives a warning. All I have done is add an extra template that matches something.
Of course, calling the second function with an empty list succeeds.
Is there a good reason why this warning occurred, or is the F # template validation just having some quirks? I could see that some cases are similar to this when more complex patterns are used, but this seems pretty simple. Even if the problem cannot be resolved as a whole, it seems like this type of case would be common enough to deserve special handling in the compiler.
I think the F # compiler is practical in this case.
At the end, the second rule can be expressed as a restriction on the input list xs :
xs = hd :: tl && xs = l The F # compiler does not seem to learn the && limitations. This is reasonable because restrictions can be arbitrarily complex, and using & 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 problem, you can:
- Use
asinstead of&, which is more appropriate sincelis just a binding. Add a template to the end to resolve the warning. I usually write
let f = function | hd::tl & l -> "Not so empty list" | _ -> "Empty list"Suppress warning with
nowarn "25".
I assume that you have found another matter (besides the when clauses and partial active patterns) where the procedure for accepting the compiler is not efficient enough. (This is why a warning message may indicate :-)).
If you want to get the same functionality without warning, then you can use a full active template like this (but actually for lists, I would probably just go with _ for an empty list, 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