On this page:
match
matches
_
_
where
where
8.13

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

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.

If an initial segment of bind patterns are literals or combinations of literals 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. The remaining patterns are handled as usual.

> 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 keyword ~fast

> match 1+2

  | n when n > 4: "ok"

match: no matching case

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

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

> 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, ’else’ substitute, 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

left_bind where

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