In C# we have
if(!String.IsNullOrEmpty(myString)) { doSomethingWithTheString(myString); } else { doSomethingInNullCase(); }
Clearly, the
doSomething...()methods will usually be more than a simple procedure, often involving local variables and transformations thereof, but the essence of the pattern is captured above.
We could, of course, transliterate this directly into F# and that is the first step in the conversion process. Thus we have
if(not <| String.IsNullOrEmpty myString) then doSomethingWithTheString(myString) else doSomethingInNullCase()
So what? I hear you say. Well, this is a step in the right direction. Functional programmers prefer pattern matching to indiscriminate use of the
ifstatement though. The question, therefore, is what pattern can we match to achieve the end and how. Crucially, in F# one cannot match against a general function. Instead one uses what is known as an Active Pattern. There are three forms of Active Patterns: single-valued, partial and multi-valued. The names are mine but they are similar to the official names. I think of 'partial' active patterns as slightly different from the other two.
First, a single-valued active pattern:
let (|EmptyString|) str = String.IsNullOrEmpty str
which could be used in this manner:
match myString with | EmptyString true -> "Empty" | _ -> "Not empty"
I think the syntax for active patterns leaves a little to be desired so let me explain what is happening here. Clearly the match is being performed on
myString. The match criterion first considered is
EmptyString. All bar the final parameter (in this case, there are no additional parameters in the match criterion) are evaluated in the context of
myString. The final parameter in the matching pattern is compared with the return value of the active pattern. In other words, the criterion is
EmptyString myStringwhich returns a
boolagainst which we match
true.
A multi-valued pattern is similar. For example:
let (|EmptyString|String|) str = if String.IsNullOrEmpty str then EmptyString else String(str)
Notice that this pattern looks much more like a discriminated union. Also, whilst it is not necessary to return a value in the 'constructor', if you will, in either case, we do so here for illustrative purposes. This pattern could be used as follows:
match String.Format("Is {0} empty?", myString) with | EmptyString -> "It's empty" | String str -> str
Thus
strholds the string that was successfully matched.
Partial active patterns are a slight change again:
let (|NotEmpty|_|) s = if String.IsNullOrEmpty s then None else Some(s)
Note that I have changed the specified portion of the pattern to
NotEmptyso that we can return the string that was matched successfully. Note also that this pattern returns an
optiontype where the multi-valued pattern returns a
Choice.
The partial pattern is used similarly:
match String.Format("Is {0} empty?", myString) with | NotEmpty str -> str | _ -> "It's empty"
As you can see, the construct is powerful and I haven't demonstrated how to pass additional parameters or match multiple values. Check Wikibooks for further information and then try the broader t'internet.