about summary refs log tree commit diff stats
path: root/js/baba-yaga/docs/03_pattern-matching.md
blob: 0bd663ed858b55766a388cdaab0276e8477e957e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# Pattern Matching

The `when` expression matches a discriminant against patterns.

## Literals and Wildcards
```baba
describe : x ->
  when x is
    0 then "Zero"
    1 then "One"
    _ then "Other";
```

## Multiple Discriminants
```baba
whereIs : x y ->
  when x y is
    0 0 then "Origin"
    1 1 then "Diagonal"
    _ _ then "Somewhere";
```

## Type Patterns
```baba
checkType : val ->
  when val is
    Int    then "Integer"
    String then "String"
    Bool   then "Boolean"
    _      then "Other";
```

## Pattern Guards

Use the `if` keyword to add conditional guards to patterns:

```baba
// Basic guards with range conditions
categorizeNumber : n ->
  when n is
    x if (x > 0) then "positive"
    x if (x < 0) then "negative"
    0 then "zero";

// Guards with complex conditions
gradeStudent : score ->
  when score is
    s if (s >= 90) then "A"
    s if (s >= 80 and s < 90) then "B"
    s if (s >= 70 and s < 80) then "C"
    s if (s >= 60 and s < 70) then "D"
    s if (s < 60) then "F"
    _ then "Invalid score";

// Type guards
processValue : value ->
  when value is
    Int if value > 100 then "large integer"
    Int if value > 0 then "positive integer"
    String if (length value) > 10 then "long string"
    String if (length value) > 0 then "short string"
    _ then "other";

// Guards with wildcard patterns
checkRange : x ->
  when x is
    _ if (x >= 1 and x <= 10) then "small"
    _ if (x >= 11 and x <= 100) then "medium"
    _ if (x > 100) then "large"
    _ then "invalid";
```

Guards are evaluated after the underlying pattern matches. The guard expression has access to any variables bound by the pattern. This allows for sophisticated conditional matching without conflicting with the `..` string concatenation operator.

## Typed discriminants

When using typed functions that return `Result`, you can pattern match on variants and bind inner values.

```baba
divide : (x: Int, y: Int) -> Result ->
  when y is
    0 then Err "Division by zero"
    _ then Ok (x / y);

use : r ->
  when r is
    Ok val  then val
    Err msg then msg;
```

## Result Patterns

```baba
divide : x y ->
  when y is
    0 then Err "Division by zero"
    _ then Ok (x / y);

use : r ->
  when r is
    Ok val  then val
    Err msg then msg;
```

## Using `with` alongside `when`

Use `with` to stage named locals used by discriminants and consequents.

```baba
classify : n ->
  with (lo Int; hi Int; lo : 10; hi : 100;) ->
    when n is
      0 then "zero"
      _ then when (n > hi) is
               true then "large"
               _    then when (n > lo) is
                           true then "medium"
                           _    then "small";
```

## List & Table Patterns

```baba
is123 : xs ->
  when xs is
    [1, 2, 3] then true
    _         then false;

hasA1B2 : t ->
  when t is
    { a: 1, b: 2 } then true
    _              then false;
```