Rohit Sharma
Rohit Sharma

Reputation: 6490

Active Pattern in match clause

I am trying to better understand how active pattern works - please correct me if i am reading active pattern wrong, taking below example:

let (|UpperCase|) (x:string) = x.ToUpper()

let result = match "foo" with
                 | UpperCase "FOO" -> true
                 | _ -> false

I see we are comparing

(Uppercase "foo") with "FOO"

but it looks odd in this case, when i read

| UpperCase "Foo"

shouldn't this code be written like

let result = match UpperCase "foo" with

Is there a better way to read?

Upvotes: 1

Views: 73

Answers (2)

kaefer
kaefer

Reputation: 5741

In your example, you are combining two patterns: the single case active recognizer without arguments UpperCase with the constant pattern "FOO". The effect is indeed the same as if you were to apply the function (|UpperCase|) inside the match expression:

match "foo" with
| UpperCase "FOO" -> true
| _ -> false
// val it : bool = true

match (|UpperCase|) "foo" with
| "FOO" -> true
| _ -> false
// val it : bool = true

Now, matching constants against constants is not very versatile, so let's make a function instead.

let isFooBarCaseInsensitive = function
| UpperCase "FOO" | UpperCase "BAR" -> true
| _ -> false
// val isFooBarCaseInsensitive : _arg1:string -> bool
isFooBarCaseInsensitive "foo"
// val it : bool = true
isFooBarCaseInsensitive "fred"
// val it : bool = false

Patterns are employed not only with the match and function keywords, but also with try...with, fun, and most notably let:

let (UpperCase foo) = "foo"
// val foo : string = "FOO"

Upvotes: 3

Chris Hannon
Chris Hannon

Reputation: 4134

Think of a match as a simplified if/else chain. For example:

match "foo" with
| "foo" -> true    
| _ -> false

Could be:

if "foo" = "foo" then true
else false

Active Patterns are implicit function calls. In your example:

match "foo" with
| UpperCase "FOO" -> true
| _ -> false

Is essentially:

if (UpperCase "foo") = "FOO" then true
else false

You're matching the result of pushing "foo" through the call, you just don't have to specify it with the usual function call syntax.

To answer your other question, in this particular case you could very well do this for the same effect:

let UpperCase (x:string) = x.ToUpper()

match UpperCase "foo" with
| "FOO" -> true
| _ -> false

It becomes a little more difficult to do that when you could have multiple pattern results that you'd like to match against, which is where Active Patterns are more useful.

For example:

let (|IsInt|IsString|) (x:obj) = match x with :? int -> IsInt | _ -> IsString

match someValue with
| IsInt -> true
| IsString -> false

Upvotes: 2

Related Questions