views:

167

answers:

3

So, I previously asked this question:

http://stackoverflow.com/questions/2820234/can-someone-help-me-compare-using-f-over-c-in-this-specific-example-ip-address

I was looking at the posted 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).

+5  A: 

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.
Nathan Sanders
Yeah it does the whole file. Not quite what I was looking for, but still good to know! :)
Phobis
In response to your second part: That works, except it wouldn't take the code exactly as you wrote... I change it to: match s.Split[|'.'|] |> Array.map parseOrParts with \n | [|a;b;c;d|] -> IP(a, b, c, d) \n | x -> failwithf "IP was not valid (%A)." x \n(Sorry, I can't figure out how to format this comment)
Phobis
Yeah, originally missing parens around `(s.Split[|'.'|])`.
Brian
Oops, I wrote this fast without testing. Fixed.
Nathan Sanders
+4  A: 

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
Brian
+3  A: 

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.

Tomas Petricek
Your first active pattern seems rather pointless, as you could just use `match` directly. About the only thing it offers is the abstraction `IPString`, which isn't really what the question was about.
Ganesh Sittampalam