Reading — step 1 of 5
Learn
~1 min readActive Patterns and Computation Expressions
Active patterns extend pattern matching with custom logic. F# unique-among-mainstream feature.
Single-case active pattern (data extraction):
let (|Lower|) (s: string) = s.ToLower()
let greet name =
match name with
| Lower "alice" -> "hi alice" // matches if .ToLower() = "alice"
| _ -> "hi stranger"
Multi-case (choose one of N variants):
let (|Even|Odd|) n =
if n % 2 = 0 then Even else Odd
let describe n =
match n with
| Even -> sprintf "%d is even" n
| Odd -> sprintf "%d is odd" n
Partial active patterns — may not match (returns Option):
let (|Int|_|) (s: string) =
match System.Int32.TryParse s with
| true, n -> Some n
| _ -> None
let parse input =
match input with
| Int n when n > 0 -> sprintf "positive int: %d" n
| Int n -> sprintf "non-positive int: %d" n
| _ -> "not an int"
The |_| says "or doesn't match" — the pattern's success is conditional.
Parameterized — take additional arguments:
let (|DivisibleBy|_|) divisor n =
if n % divisor = 0 then Some () else None
let fizzBuzz n =
match n with
| DivisibleBy 15 -> "FizzBuzz"
| DivisibleBy 3 -> "Fizz"
| DivisibleBy 5 -> "Buzz"
| _ -> string n
Note () means "matched, but no value extracted."
Use cases:
- Parsing (
Int,Email,Date) - Domain extraction (
UserId,OrderState) - Regex pattern matching (libraries provide
(|Regex|_|)) - Test assertions
Active patterns combine the readability of pattern matching with custom predicates — what is X checks would do in less expressive languages.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…