Reputation: 1776
My question is inspired by this one: link
Here is a code:
type A =
| X of int * int
| Y of string
let f (A.X(a, b)) = a + b
It works, but with a warning:
Makes sense; I have no match for Y.
But if I add a line
let f (A.Y(s)) = 10
Then I get an error:
Is there a nice way to fix it and still use pattern matching in function parameters? If not, then why did they create such strange syntax, which always leads to a warning?
Upvotes: 4
Views: 498
Reputation: 3687
Some pattern matches can be complete and might be useful in function parameters, e.g. this definition of fst
is pattern matching a tuple and is complete for all 2 tuples.
let fst (a,_) = a
Some other examples:
type Container = Container of string
let unwrap (Container(v)) = v
type Person = { Name:string; Age:int }
let getName {Name=name} = name
Upvotes: 4
Reputation: 7735
As other answers say, the best way seems to be using pattern matching with function
or match
keywords.
However, native pattern matching of F# is pretty much powerful thing by itself. Consider the code below, however I'm not advocating to use it in a real-world project. I would rather use it as an exercise for better understanding of the language.
let f ((A.X(a, b), _ ) | (A.Y(_), (a, b))) = a + b
// usage
let x1 = f(A.X(10, 42), (100, 1)) // x1 = 52
let x2 = f(A.Y("foo"), (100, 1)) // x2 = 101
What's going on here?
A.X
or provided as a separate argument;A.Y(string)
, we still need to sum something.A.X(int, int)
.Yet again, don't use it blindly in real-world projects since it doesn't seem to be readable.
Further reading: A similar approach for list processing.
Upvotes: 2
Reputation: 144136
You need to pattern match on the argument:
let f = function
| X(a, b) -> a + b
| Y(_) -> 10
When you define
let f (A.X(a, b)) = a + b
f
has type A -> int
, not A.X -> int
. It is not defined for values which are instances of A.Y
, so you get the incomplete match warning.
Your second definition of f
also has type A -> int
and so is a duplicate definition of the first, hence the error. If you want to write a total function over some union type you should use pattern matching with function
or match
.
EDIT: In response to the comment, if you have multiple arguments you want to match at the same time, you can use match
e.g.:
let f a1 a2 =
match (a1, a2) with
| (X(a, b), X(a', b')) -> a + b
| (X(a, b), Y(s)) -> a + 10
| (Y(s), X(a, b)) -> 10
| (Y(s), Y(s')) -> 20
Upvotes: 8