ESC
Type to search...
S
Soli Docs

Pattern Matching

Powerful pattern matching with match expressions, destructuring, and guard clauses.

Basic Match

match

Match a value against patterns and execute corresponding code.

let x = 42;
let result = match x {
    42 => "the answer",
    0 => "zero",
    _ => "something else",
};
print(result);  // "the answer"

Guard Clauses

Add conditions to patterns using if guards:

let n = 5;
let category = match n {
    n if n < 0 => "negative",
    0 => "zero",
    n if n > 0 && n < 10 => "single digit positive",
    n if n >= 10 && n < 100 => "two digit positive",
    _ => "large number",
};
print(category);  // "single digit positive"

// Practical example: HTTP status handling
fn handle_status(code: Int) -> String {
    return match code {
        code if code >= 200 && code < 300 => "Success: " + str(code),
        code if code >= 300 && code < 400 => "Redirect: " + str(code),
        404 => "Not Found",
        500 => "Internal Server Error",
        code if code >= 500 => "Server Error: " + str(code),
        _ => "Client Error: " + str(code),
    };
}

print(handle_status(200));  // "Success: 200"
print(handle_status(404));  // "Not Found"

Array Patterns

let numbers = [1, 2, 3];

// Match array length
let description = match numbers {
    [] => "empty array",
    [_] => "single element array",
    [_, _] => "two element array",
    [_, _, _] => "three element array",
    _ => "array with more than 3 elements",
};

// Destructuring arrays
let result = match numbers {
    [first] => "First element is: " + str(first),
    [first, second] => "First: " + str(first) + ", Second: " + str(second),
    [first, second, third] => "Three elements",
    [first, ...rest] => "First: " + str(first) + ", Rest has " + str(len(rest)) + " elements",
};

// Rest pattern
let arr = [1, 2, 3, 4, 5];
match arr {
    [first, second, ...rest] => {
        print("First two: " + str(first) + ", " + str(second));
        print("Remaining: " + str(rest));  // [3, 4, 5]
    },
};

Hash Patterns

let user = {"name": "Alice", "age": 30, "city": "Paris"};

// Match hash structure
match user {
    {} => "empty object",
    {name: n} => "name is: " + n,
    {name: n, age: a} => n + " is " + str(a) + " years old",
    {name: n, age: a, city: c} => n + " is " + str(a) + " years old and lives in " + c,
    _ => "unknown structure",
};

// Nested hash matching
let data = {
    "user": {"name": "Alice", "email": "[email protected]"},
    "posts": [{"title": "Post 1"}, {"title": "Post 2"}]
};

match data {
    {user: {name: n}, posts: posts} => {
        print(n + " wrote " + str(len(posts)) + " posts");
    },
    _ => "no match",
};

Type-Based Dispatch

fn describe_value(val: Any) -> String {
    return match val {
        s: String => "String with " + str(len(s)) + " characters",
        n: Int => "Integer: " + str(n),
        f: Float => "Float: " + str(f),
        b: Bool => "Boolean: " + str(b),
        arr: Array => "Array with " + str(len(arr)) + " elements",
        h: Hash => "Hash with " + str(len(h)) + " keys",
        null => "Null value",
        _ => "Unknown type: " + type(val),
    };
}

print(describe_value("hello"));     // "String with 5 characters"
print(describe_value(42));          // "Integer: 42"
print(describe_value([1, 2, 3]));   // "Array with 3 elements"

Wildcard Pattern

_ Wildcard / Default Case

Matches any value. Use as a default/catch-all case.

let status = "unknown";
let message = match status {
    "active" => "User is active",
    "inactive" => "User is inactive",
    _ => "Status: " + status,  // Default case
};