Single-case Active Patterns vs Function Calls
In response to an earlier post a reader wrote:
Sent From: namin
Subject: (|EnsurePrefix|) -- why is it an active pattern?
__________________________________
Hi Chris,
I was reading your blog entry Regular Expressions via Active Patterns and I am puzzled as to why you decided to make |EnsurePrefix| an active pattern. It seems like you're just using as a function, so what's the benefit?
Thanks. Best Regards,
~n
Namin is correct. A single-case Active Pattern can be thought of as a function call, simply taking one value and returning another. The benfit to using an Active Pattern instead, is that unlike function calls Active Patterns can be used directly in pattern matching. Whereas to match on the result of an arbitrary function call, you need to add a 'when' guard to the pattern match.
Example:
#light
// Using single-case Active Patterns. (A multi-case active pattern would be
// preferable in this situation, but this is just an example.)
let (|IsAllCaps|) (x:string) = (x = x.ToUpper())
let (|IsAllLower|) (x:string) = (x = x.ToLower())
let (|MixedCase|) (x:string) = (x <> x.ToLower() && x <> x.ToUpper())
let testActivePatterns x =
match x with
| IsAllCaps true -> printfn "%s is in all caps" x
| IsAllLower true -> printfn "%s is in all lower" x
| MixedCase true -> printfn "%s has mixed case" x
| _ -> failwith "Shouldn't get here."
// Using Function Calls
let isAllCapsFunc (x:string) = (x = x.ToUpper())
let isAllLowerFunc (x:string) = (x = x.ToLower())
let isMixedFunc (x:string) = (x <> x.ToLower() && x <> x.ToUpper())
let testFunctionCalls x =
match x with
| _ when isAllCapsFunc x = true -> printfn "%s is in all caps" x
| _ when isAllLowerFunc x = true -> printfn "%s is in all lower" x
| _ when isMixedFunc x = true -> printfn "%s has mixed case" x
| _ -> failwith "Shouldn't get here."
So while single-case Active Patterns may seem like a somewhat complex way to write a function call, they add a lot of succinctness to the language. Thanks for the question!