Reputation: 9113
I understand how active patterns can be defined and used in F#, including partial active patterns, and the different sorts of patterns available. E.g.
let (|Big|Small|) animal = if animal.IsBig then Big(animal) else Small(animal)
let f = function | Big(_) -> "big" |Small(_) -> "small
However, I'm confused regarding using active patterns and discriminated unions in let
bindings, arguments, and other places. For example, the MSDN has the following code:
let GetSubstring1 (Slice(p0, p1, text)) =
printfn "Data begins at %d and ends at %d in string %s" p0 p1 text
text.[p0..p1]
Which confuses me a bit.
A specific issue. Let's say I have the discriminated union,
type Union = A of int * int | B of int
Can I somehow make a function that accepts only Union.A
, e.g.
let f (A(a, b)) = a + b
In this situation, it tells me there are unmatched patterns. Is there a way to satisfy it?
Upvotes: 3
Views: 345
Reputation: 243051
As noted by @ildjarn, this applies to all patterns. They can appear in cases of the match
clause (and in function
which is similar), but also in the parameter declaration of let
bound function and even in the let
value binding.
The key difference is that with let
, you only want to use complete patterns that will always succeed. This is not needed for match
or function
, because there are multiple clauses, so if the first one fails, the matching can continue and try the next one.
For example, the following complete pattern takes int
and returns it as a string
:
let (|AsString|) (n:int) = n.ToString()
Here are some ways how you can use it:
let (AsString s) = 42 // Defines a value 's' of type string
match 3 with AsString s -> s // Returns a value "3" of type string
let convert (AsString s) = s // Defines a function 'int -> string'
let convert = function AsString s -> s // Same as the previous line
EDIT: To answer your second question, if you use let
with an incomplete pattern (i.e. that accepts only a single case of a discriminated union) then you get a compiler warning and the code may fail at runtime (if you call it with the other discriminated union case):
let f (A(a, b)) = a + b // This gives compile-time warning
f (B 42) // This will fail at runtime
If you need to define a function that works only one of the cases, then you need to define a separate type.
type AInfo = int * int
type Union = A of AInfo | B of int
Then you can write a function that will only take AInfo
(but you can still work with Union
in places where both options represent a valid input).
Upvotes: 8