On this page:
match
matches
_
_
where
where
8.15.0.12

5.2 Matching🔗ℹ

expression

match target_expr

| bind:

    result_body

    ...

| ...

 

expression

match target_expr

| bind:

    result_body

    ...

| ...

| ~else:

    result_body

    ...

 

expression

match target_expr

| bind:

    result_body

    ...

| ...

| ~else result_expr

Tries matching the result of target_expr against each bind in sequence, and as soon as one matches, returns the result of the corresponding result_body block. The keyword ~else can be used as a synonym for _ (which matches any value without binding any identifiers) in the last clause.

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.

> match 1+2

  | 3: "three"

  | ~else: "not three"

"three"

> match [1+2, 3+4]

  | [x, y]: x+y

10

> match 'go ~slow'

  | 'go ~fast': "ok"

match: expected the literal #:fast

> match 1+2

  | 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.

> match 1+2

  | 4: "four"

match: no matching case

> match '1+2'

  | '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.

> use_static

> match (["apple", "banana"] :: List.of(String))

  | [s, ...]: [s.length(), ...]

[5, 6]

expression

expr matches bind

Produces #true if the value of expr matches bind, #false otherwise. Equivalent to expr is_a matching(bind).

> [1, 2, 3] matches [_, _, _]

#true

> [1, 2, 3] is_a matching([_, _, _])

#true

binding operator

_

Matches any value without binding any identifiers.

> match 1+2

  | 0: "zero"

  | _: "nonzero"

"nonzero"

expression

_

As an expression by itself, _ is a syntax error, but _ is recognized by #%parens and #%call in expression-like positions to trigger a function-shorthand conversion.

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.

> def subtract = (_ - _)

> subtract(2, 1)

1

> [1, 2, 3].map((_ + 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.

> [1, 2, 3].map(_ + 1)

_: 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

left_bind where right_bind = expr

 

binding operator

left_bind where:

  right_bind_and_expr

  ...

 

right_bind_and_expr

 = 

right_bind = expr

 | 

right_bind:

  body

  ...

Creates a binding that matches only when both left_bind matches and when each right_bind matches the value of the corresponding expr or body sequence. Names bound by left_bind and each right_bind are visible in exprs and body sequences for subsequent right_binds.

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.

> def ([x, y, z] where sum = x+y+z) = [1, 2, 3]

> '$x $y $z'

'1 2 3'

> sum

6

fun

| f(([x, y, z] where sum = x+y+z) when sum == 6):

    '$x $y $z = $sum'

| f(_):

    "something else"

> f([1, 2, 3])

'1 2 3 = 6'

> f([0, 2, 3])

"something else"

> def ([x, y, z] where:

         partial_sum = x+y

         sum = partial_sum+z):

    [1, 2, 3]

> sum

6

> def ([xs] where [x, ...] = xs) = [[1, 2, 3]]

> '$x ...'

'1 2 3'

> def ([xs] where [x, ...] = xs) = ["oops"]

def: value does not satisfy annotation

  value: ["oops"]

  position: 1st

  annotation: matching(List(_)) where ....

expression

where

 

expression

expr where

As an expression operator, where always reports a syntax error.