The reason you're getting that error is because of what F# is doing when you use a variable name in the pattern clause of a match expression.
Let's say I have
match arg with
| x when x = 0 -> "zero"
| y when y = 1 -> "one"
| _ -> "other"
I think it's key here to note that, despite not defining x or y prior to the match, this code will still work. This is because x and y are just short codes which makes writing match expressions easier. Behind the scenes, the F# compiler is actually converting that x when x = 0
into "let binding" where x
is bound to arg
. x
can then be used in the x = 0
expression and in the expression after the ->
.
Going back to the problem you ran into:
let key1 = 1
let key2 = 2
let value =
match arg with
| key1 -> "value1"
| key2 -> "value2"
| _ -> failwith "key not found"
The reason this won't work, is because in the match expression, F# is rebinding key1
to the value of arg
, so key1 -> "value1" is equivalent to
if arg1 = arg1 then "value1". The first pattern will always be matched; so, key2
and _
will never be reached.
I'm not sure how clear my explanation is, so I'll also throw in a second approach to explaining what's happened:
if you translate the match expression into an if-else it would look like this:
let key1 = 1
let key2 = 2
let value =
if let key1 = arg in arg = key1 then
"value1"
else if let key2 = arg in arg = key2 then
"value2"
else
failwith "key not found"
(why yes, F# will let you throw let bindings into if expressions)
This if/else expression is equivalent to your match expression. In this form it becomes clear that the first condition will always evaluate to true.
I won't put it in here, but it may help to look at the code quotation of a match expression. I didn't really get what was going on with match expressions until I saw what the abstract syntax tree they generated looked like.
arg
defined? – Mcdowellarg
is defined locally in the function, but I believe it is the same if it's a function argument – Teresetereshkova