"Not so empty list" It works gre...">

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.

+6
source share
2 answers

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 as instead of & , which is more appropriate since l is 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" .

+6
source

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 
+4
source

Source: https://habr.com/ru/post/952335/


All Articles