5.2 Matching
expression | ||||||||
| ||||||||
| ||||||||
expression | ||||||||
| ||||||||
| ||||||||
expression | ||||||||
|
Typically, a bind imposes requires on a value and binds some number of identifiers as a result of a successful match. For example, a literal number works as a bind pattern, but it binds zero identifiers. An identifier as a bind pattern matches any value and binds the identifier the the matching value. A list form is a bind pattern with subpatterns as its elements, and it matches a list with the right number of elements that match match the corresponding pattern. A when or unless can impose a side condition on a match. The set of bind forms is extensible, so it cannot be completely enumerated here.
| 3: "three"
| ~else: "not three"
"three"
| [x, y]: x+y
10
> match 'go ~slow'
| 'go ~fast': "ok"
match: expected the literal #:fast
| n when n > 4: "ok"
match: no matching case
If no target_expr produces a true value and there is no ~else clause, a run-time exception is thrown. In that case, when all of the bind forms are syntax-object patterns, the generated exception’s message may be specialized to report the expected pattern, instead of just reporting that no cases matched.
| 4: "four"
match: no matching case
| '4': "four"
match: expected the literal 4
If an initial segment of bind patterns are “literal-like” or combinations of such patterns with ||, then the match is implemented as a case dispatch, and a match is found with logarithmic rather than linear time complexity in the number of literals. “Literal-like” patterns include (usually implicitly used) #%literal, #', Char, and Byte. The remaining patterns are handled as usual.
fun classify_efficiently(n):
match n
| 1: "one"
| 2: "two"
| 3 || 4: "some"
| ~else: "more"
Static information for target_expr is propagated to each bind.
| [s, ...]: [s.length(), ...]
[5, 6]
#true
#true
binding operator | |
| 0: "zero"
| _: "nonzero"
"nonzero"
expression | |
The #%parens conversion applies when (…) are used in an expression position, and at least one _ appears immediately within the parentheses as in (term ... _ term ...). An immediate _ is one that is not more deeply nested in a term within the parentheses. A single immediate _ is replaced by a fresh identifier id as an expression, and then the parenthesized sequence is placed in the body of a function that uses the identifier as an argument, as in (fun (id): term ... id term ...). If multiple immediate _s are present, each one is replaced by a distinct identifier, the identifiers are used as the arguments of the generated function, and the arguments match the order of the corresponding _. Moreover, static information is gathered from the parenthesized sequence, by parsing it as an expression, and propagated as result information.
> subtract(2, 1)
1
[2, 3, 4]
The #%call conversion applies when (…) are used after an expression, at least one _ appears by itself as an argument, and no argument uses & or is a repetition followed by a .... Each _ argument is converted as in the #%parens conversion, but the conversion applies only for a _ that appears by itself in the group for function-call argument. Moreover, result information is gathered from the inner function and propagated to the outer function.
> def low_bits = bits.field(_, 0, 3)
> low_bits(15)
7
> [1.25, 2.75, 3.0].map(math.round(_))
[1.0, 3.0, 3.0]
A _ combined with other terms as a function-call argument does not trigger a function-shorthand conversion.
_: not allowed as an expression;
only allowed as binding pattern or anonymous-function argument,
and use isn’t an allowed position to create a function
binding operator | ||||||||||
| ||||||||||
binding operator | ||||||||||
| ||||||||||
| ||||||||||
|
The where form should generally be used with parentheses around it, since parsing is otherwise likely to interact badly with the enclosing context, such as conflicting interpretations of a = by where and def.
> f([1, 2, 3])
'1 2 3 = 6'
> f([0, 2, 3])
"something else"
def: value does not satisfy annotation
value: ["oops"]
position: 1st
annotation: matching(List(_)) where ....