The F# compiler performs a certain analysis when a name (identifier) occurs in the position of a pattern case. Strictly speaking, there are some opportunities for the name to be as follows:
None
if matching an F# option
)System.ArgumentException
if matching an exception type)If the name occurrence does not fit any of the previously listed alternatives, the name is considered a variable pattern (https://msdn.microsoft.com/en-us/library/dd547125.aspx
). It is treated similarly to the wildcard pattern, getting the value of comparison-expression
parameter, which can be used in the corresponding result-expression
. Sounds confusing, right? Then let's turn to a sample in order to make this matter clear.
I just took the definition of the transformA
function from the matching literals section, changed the name of the function to transformA'
, and removed the definition of the THREE
literal from the context (Ch4_2.fsx
):
let transformA' v = match v with | 1 -> "1" | 2 -> "2" | THREE -> "3"
The results of experimenting with this function version are shown in the following screenshot.
To begin with, the omission of the literal didn't blow up the script, producing just a benign warning that THREE
might be a misspelled pattern name. Applying the function to the argument 50
that is completely off produces the same result as before for the legitimate argument value 3
. What gives?
No magic here; in accordance with the description identifier, THREE
was not recognized as a named literal, discriminated union case, exception type, or active pattern. This finding turned it into a variable pattern playing the role of a match-all pattern case, which result-expression
just blindly outputs as string "3".
In my experience as an F# developer, I faced at least one occasion when this seemingly innocuous pattern type transformation typo turned into a nasty bug.