Introducing Active Patterns in Kit

Back to Blog

Active Patterns are now available in Kit v2026.3.7 and later. Inspired by F#'s active patterns, this feature enables powerful, reusable pattern matching logic.

We're excited to announce that Active Patterns have arrived in Kit! This powerful feature, inspired by F#'s active patterns, allows you to define reusable, composable pattern matching logic that integrates seamlessly with Kit's existing match expressions.

What Are Active Patterns?

Active patterns are functions that participate in pattern matching. Unlike regular patterns that match on structure, active patterns can execute arbitrary logic to determine if a value matches, and can extract and transform values in the process.

An active pattern function returns Option T:

Defining Active Patterns

Use the pattern keyword to define an active pattern:

# Define a pattern that matches positive numbers
pattern positive = fn(n) =>
  if n > 0 then Some n else None

# Define a pattern that matches even numbers
pattern even = fn(n) =>
  if n % 2 == 0 then Some n else None

# Define a pattern that matches values in a specific range
pattern in-range = fn(min, max, n) =>
  if n >= min and n <= max then Some n else None

Using Active Patterns

Active patterns work in match expressions just like built-in patterns:

# Use active patterns in match expressions
classify = fn(n) =>
  match n
    | positive x -> "${x} is positive"
    | _ -> "not positive"

println (classify 42)   # => 42 is positive
println (classify -5)   # => not positive

AND Pattern Composition

One of the most powerful features of active patterns is the ability to compose them with the and keyword. This allows you to require multiple patterns to match simultaneously:

pattern small = fn(n) =>
  if n < 10 then Some n else None

# Both patterns must match, both variables are bound
result = match 5
  | positive x and small y -> x + y
  | _ -> 0

println result  # => 10 (5 + 5)

In this example:

Value Extraction and Transformation

Active patterns can do more than just match - they can extract and transform values:

# Pattern that doubles the matched value
pattern double-it = fn(n) => Some (n * 2)

# Pattern that extracts the first character of a string
pattern first-char = fn(s) =>
  if String.length s > 0 then Some (String.char-at s 0) else None

result = match 7
  | double-it x -> x
  | _ -> 0

println result  # => 14

Practical Examples

Validation

pattern valid-age = fn(age) =>
  if age >= 0 and age <= 150 then Some age else None

pattern adult = fn(age) =>
  if age >= 18 then Some age else None

check-person = fn(age) =>
  match age
    | valid-age a and adult _ -> "Valid adult: ${a}"
    | valid-age a -> "Valid minor: ${a}"
    | _ -> "Invalid age"

String Parsing

pattern digit = fn(c) =>
  if c >= "0" and c <= "9" then Some c else None

pattern vowel = fn(c) =>
  vowels = ["a", "e", "i", "o", "u"]
  if List.contains? vowels c then Some c else None

Implementation Status

Active Patterns are now fully implemented in Kit v2026.3.7:

Next Steps

Ready to try Active Patterns? Check out the documentation:

Active patterns open up new possibilities for clean, reusable pattern matching in Kit. We're excited to see what you build with them!