开发者

Is it possible, with simple F# pattern matching transformations, to ignore unmatched values without a warning?

So, I previously asked this question:

Can someone help me compare using F# over C# in this specific example (IP Address expressions)?

I was looking at the poste开发者_如何学运维d code and I was wondering if this code could be written without it producing a warning:

let [|a;b;c;d|] = s.Split [|'.'|]
IP(parseOrParts a, parseOrParts b, parseOrParts c, parseOrParts d)

Is it possible to do something for the match _ pattern ot ignore? Without adding in something like Active Patterns? i want to keep the code as simple as possible... can I do this without drastically changing this code?

NOTE: Warning is as follows

Warning Incomplete pattern matches on this expression. For example, the value '[|_; _; _; _; _|]' may indicate a case not covered by the pattern(s).


You might try

#nowarn "25"

before the partial function.

But of course you're disabling a warning, and I think this turns it off for the whole file. I remember seeing a way to disable warnings for only part of a file, but I can't find it right now.

There is also the compiler option --nowarn:25, but this is even worse since it applies to the whole project.


To do this the Right Way, you need to replace your two lines with three:

match Array.map parseOrParts (s.Split [|'.'|]) with
| [|a;b;c;d|] -> IP(a,b,c,d)
| _ -> failwith "Oh no!"   // preferably, your exception of choice goes here.


Note that the warning is telling you that if there are not exactly 4 elements after the String.Split call, you'll get a MatchFailureException.

As others have said, the best way to get rid of the warning is

match s.Split(...) with
| [| a; b; c; d |] -> blah(a,b,c,d)
| _ -> raise <| new Exception("Expected exactly 4 parts") // or whatever


I know that you wrote "without adding things like Active Patterns", but I'll post a solution that uses them anyway. They are a perfect match for problems like this and they are a pretty standard F# feature, so there is really no reason why you would want to avoid them. Using active patterns here makes the code definitely more readable.

(If you're F# beginner than I can understand why you want to start with a simple solution - anyway, this may be a good motivation for you to learn active patterns eventually :-), they are not as difficult as they may appear for the first look)

You can define an active patter that matches if the string is formatted as an IP address (consisting of four substrings separated by "."):

let (|IPString|_|) (s:string) =
  match s.Split('.') with
  | [|a;b;c;d|] -> Some(a, b, c, d) // Returns 'Some' denoting a success
  | _ -> None                       // The pattern failed (string was ill-formed)

match s with 
| IPString(a, b, c, d) ->  
    // Matches if the active pattern 'IPString' succeeds and gives
    // us the four parts of the IP address (as strings)
    (parseOrParts a, parseOrParts b, parseOrParts c, parseOrParts d)
| _ -> failwith "wrong format"

This is the proper way that allows you to handle the case when the string is incorrect. You can of course define a version that never fails (and returns for example 0.0.0.0 if the string is ill-formed):

// This active pattern always succeeds, so it doesn't include the "|_|" part 
// in the name. In both branches we return a tuple of four values.
let (|IPString|) (s:string) =
  match s.Split('.') with
  | [|a;b;c;d|] -> (a, b, c, d)
  | _ -> ("0", "0", "0", "0")

let (IPString(a, b, c, d)) = str
(parseOrParts a, parseOrParts b, parseOrParts c, parseOrParts d)

I think most of the people would agree that this is more readable. Of course, if you want to write something simple just for a single purpose script, then you can just ignore the warning, but for anything larger, I'd prefer active patterns.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜