Reputation: 6490
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
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
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