A pattern tests the shape of a value and binds names to parts of it. Patterns appear in match and function arms, in try … with handlers, in let bindings, in lambda and function parameters, in for loops and in let!.
Match expressions
let describe x =
match x with
| 0 -> "zero"
| n when n < 0 -> "negative" // a guard with when
| 1 | 2 | 3 -> "small" // an or-pattern
| _ -> "large"
let length = function // function: a lambda that matches its argument
| [] -> 0
| _ :: tail -> 1 + length tail
let Some value = Some 3 // a pattern in a let (incomplete: a warning)
| is optional; the result of every rule has the same type.The compiler warns when the rules are incomplete (FS0025) or when a rule can never be reached. A when guard is any boolean expression and may use the names the pattern bound. match! matches on the result of a computation expression step.
Pattern forms
| Pattern | Form | Example |
|---|---|---|
| constant | a numeric, character or string literal, an enum case, a [<Literal>] name | 1.0 "test" Color.Red |
| identifier | a union case, an exception name or an active pattern case, with its argument patterns | Some x Failure msg Circle r |
| variable | a lower-case name that binds the value | a |
as | binds the whole value that matched the pattern on the left (a pattern may follow as from F# 6) | (a, b) as pair |
| or | either pattern; both must bind the same names | [ h ] | [ h; _ ] |
| and | both patterns must match | (a, _) & (_, "test") |
| cons | head and tail of a list | h :: t |
| list | a list of fixed length | [ a; b; c ] |
| array | an array of fixed length | [| a; b |] |
| tuple | a tuple (struct (a, b) for a struct tuple) | (a, b) |
| record | some or all of the fields of a record | { Name = name } |
| union with named fields | fields by name | Rectangle(height = h; width = w) |
| wildcard | anything, not bound | _ |
| type annotation | a pattern with its type | a : int |
| type test | the value has the type (or a subtype); as binds it with that type | :? System.DateTime as dt |
| null | the null value | null |
| nameof | the string that nameof gives | nameof str |
| parenthesised | grouping | ( a ) |
A name in a pattern is a variable if it starts with a lower-case letter and is not a case of a union, an exception, an active pattern or a literal in scope; that is why constants meant for matching should start with a capital letter. A pattern names each variable once (apart from or-patterns). A pattern on the left of let or fun must be complete or the compiler warns.
type Shape = Circle of float | Rect of float * float
let area = function
| Circle r -> 3.14 * r * r
| Rect (w, h) when w = h -> w * w
| Rect (w, h) -> w * h
let rec sum = function [] -> 0 | x :: rest -> x + sum rest
let handle (o: obj) =
match o with
| :? string as s -> s.Length
| :? int as i when i > 0 -> i
| null -> -1
| _ -> 0
let first, second = (1, 2)
let { Name = n } = { Name = "x"; Age = 3 }
Active patterns
An active pattern is a function whose name is written between banana clips (| … |); it can be used in a pattern like a union case. The name inside lists the cases.
| Kind | Definition | Returns |
|---|---|---|
| single-case | let (|Name|) x = … | the value to match against the argument pattern |
| multi-case (up to seven) | let (|Even|Odd|) n = … | one of Choice1Of2-style cases: the expression gives Even or Odd (with a value if the case has one) |
| partial | let (|Int|_|) s = … | Some value or None; since F# 9 also a bool when there is nothing to bind; with [<return: Struct>] a ValueOption |
| parameterised | let (|Div|_|) d n = … | takes extra arguments before the value, given in the pattern: Div 3 |
let (|Even|Odd|) n = if n % 2 = 0 then Even else Odd
let (|Int|_|) (s: string) =
match System.Int32.TryParse s with
| true, v -> Some v
| _ -> None
[<return: Struct>]
let (|Positive|_|) n = if n > 0 then ValueSome n else ValueNone
let (|Divisible|_|) d n = if n % d = 0 then Some () else None
let classify s =
match s with
| Int (Even) -> "even number"
| Int n when n < 0 -> "negative"
| Int _ -> "odd number"
| _ -> "text"
let fizz = function Divisible 15 -> "FizzBuzz" | Divisible 3 -> "Fizz" | n -> string n
A complete (multi-case or single-case) active pattern is checked for completeness; a partial one is not, so a wildcard rule is needed. The name (|A|B|) counts as one definition: A and B are not values. Library active patterns include (|Failure|_|), (|KeyValue|), (|Null|NonNull|) and, in quotation code, those of Microsoft.FSharp.Quotations.Patterns (see quotations).
Not described
Known, not yet covered
- Reference: the compilation of matches (decision trees), the exact exhaustiveness rules, the pattern-matching rules for literals of enum types and for byref patterns, the full list of
Operatorsactive patterns, and the details ofaspatterns that bind in a pattern on the right (F# 6) are not described. - Reference: the pattern table is from the documentation’s Pattern Matching page; the active pattern table and examples were written from its structure and the F# 9 bool return and struct return notes, and were not compiled.
See also
- Types – the unions, records and tuples that patterns take apart
- Expressions and control flow –
matchamong the other expressions