开发者

Problems with pattern matching in F#

I need help with p开发者_运维百科aternmatching in F#. I want to do this:

            let y x =
            match x with
            | x.Contains("hi") -> "HELLO"
            | x.Contains("hello") -> "HI"
            | x -> x

But it doesn't work. What's wrong?


The easiest approach is to use a when guard in your match cases.

let y (x:string) =
  match x with
  | x when x.Contains("hi") -> "HELLO"
  | x when x.Contains("hello") -> "HI"
  | x -> x


Conditions that include method calls can be only written in the when guard as pblasucci writes.

If you want to use some advanced F# features (e.g. if you need to write this a lot), then you can define active pattern to check for substring (but don't worry about this if you're just learning F#):

let (|Contains|_|) (what:string) (str:string) = 
  if str.Contains(what) then Some(str) else None

Then you can write something like (interestingly, you can also use nested patterns to check for multiple words, but the same thing could be written using & pattern):

match "hello world" with
| Contains "hello" (Contains "world" str) -> 
    printfn "%s contains both hello and world!" str
| Contains "hello" str -> 
    printfn "%s contains only hello!" str
| _ -> ()


I think my answer here to a previous question may help you understand pattern matching a little better.

However, for what you are trying to do, I'd probably stick with simple if/then/else expressions:

let y x =
  if x.Contains("hi") then "HELLO"
  elif x.Contains("hello") then "HI"
  else x

Creating a special Contains active pattern like @Tomas Petricek shows is also an option, but I find that if I am actually going to be doing some serious string pattern matching, then I just stick with a couple faithful regex active patterns:

open System.Text.RegularExpressions

///Match the pattern using a cached interpreted Regex
let (|InterpretedMatch|_|) pattern input =
    if input = null then None
    else
        let m = Regex.Match(input, pattern)
        if m.Success then Some [for x in m.Groups -> x]
        else None

///Match the pattern using a cached compiled Regex
let (|CompiledMatch|_|) pattern input =
    if input = null then None
    else
        let m = Regex.Match(input, pattern, RegexOptions.Compiled)
        if m.Success then Some [for x in m.Groups -> x]
        else None

and for this problem, use them like so:

let y = function // shorthand for let y x = match x with ...
    | CompiledMatch @"hi" _ -> "HELLO"
    | CompiledMatch @"hello" _ -> "HI"
    | x -> x

I like this because it covers Contains, StartsWith, EndsWith, Equals, and beyond with ease:

let y = function
    | CompiledMatch @"^hi$" _ -> "Equals"
    | CompiledMatch @"^hi" _ -> "StartsWith"
    | CompiledMatch @"hi$" _ -> "EndsWith"
    | CompiledMatch @"leadinghiending" _ -> "Beyond"
    | CompiledMatch @"hi" _ -> "Contains"
    | x -> x

(note that the literal strings, introduced by @, are not actually needed for any of these regex examples, but as a matter of habit, I always use them since you need them more often than not with regular expressions).

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜