パタン・マッチングは, 構造化データをその構成部品に分解したり, 検査するのを容易にする言語フィーチャです. ほとんどのプログラミング言語では構造化データを構築するためにはよく知られた方法を提供していますが, パタン・マッチングは構造化データを分解し, その断片を指定した名前に束縛してスコープに持ち込めるようにするものです. 構文上は, パタンは構造化データの構築に似ていますが, 一般的には, 関数の引数の位置, switch 式の case キーワードの後, letvar 宣言の後など入力方向の場所に置かれます.

Pattern matching is a language feature that makes it easy to both test and decompose structured data into its constituent parts. While most programming languages provide familiar ways to build structured data, pattern matching enables you to take apart structured data and bring its fragments into scope by binding them to the names you specify. Syntactically, the patterns resemble the construction of structured data, but generally appear in input-direction positions, such as in function argument positions, after the case keyword in switch expressions, and after let or var declarations.

下の関数呼び出しを見てください:

Consider the following function call:

let name : Text = fullName({ first = "Jane"; mid = "M"; last = "Doe" });

このコードでは, 三つのフィールドを持つレコードを作成し, それを fullName 関数に渡しています. 呼び出しの結果を識別子 name に束縛して, 名前を付けてスコープに持ち込んでいます. 最後に, 束縛のステップはパタン・マッチングと呼ばれ, name: Text はパタンのもっとも単純なもののひとつです. 例えば次の呼び出される側の実装では:

This code constructs a record with three fields and passes it to the function fullName. The result of the call is named and brought into scope by binding it to the identifier name. The last, binding step is called pattern matching, and name : Text is one of the simplest forms of pattern. For instance, in the following implementation of the callee:

func fullName({ first : Text; mid : Text; last : Text }) : Text {
  first # " " # mid # " " # last
};

入力は (無名の) オブジェクトで, 三つの Text に分解され, その値は識別子 first, mid, last に束縛されています. これらは, この関数の本体を構成するブロック中では自由に使うことができます. 上では, オブジェクトのフィールドのパタンに対して 名前パニング (エイリアシングの一形式) を使って, フィールドの値をフィールドの名前に束縛しています. フィールド・パタンのより一般的な形式では, …; mid = m : Text; … のようにフィールドとは別の名前付けができます. ここでは, パタンのスコープ内で mid がマッチするフィールを決め, m がこのフィールドの内容に名前を付けています.

The input is an (anonymous) object, which is destructured into its three Text fields, whose values are bound to the identifiers first, mid and last. They can be freely used in the block that forms the body of the function. Above we have resorted to name punning (a form of aliasing) for object field patterns, using the name of a field to also name its contents. A more general form of field pattern allows the content to be named separately from the field, as in …; mid = m : Text; …. Here mid determines which field to match, and m names the content of that field within the scope of the pattern.

リテラル・パタン を宣言してパタン・マッチングを使うこともできます. これはリテラル定数のように見えます. 例えば:

You can also use pattern matching to declare literal patterns, which look just like literal constants. Literal patterns are especially useful in switch expressions because they can cause the current pattern match to fail, and thus start to match the next pattern. For example:

switch ("Adrienne", #female) {
  case (name, #female) { name # " is a girl!" };
  case (name, #male) { name # " is a boy!" };
  case (name, _) { name # ", is a human!" };
}

一行目は, 最初の case 句にマッチし (識別子 name への束縛は失敗しないはずなので, ヴァリアント・リテラルの短縮形 #Female と等号で比較する), "Adrienne is a girl!" に評価されます. 最後の句は ワイルドカード パタン _ の使用例です. 必ず成功しますが, どの識別子にも束縛されません.

  1. will match the first case clause (because binding to the identifier name cannot fail and the shorthand variant literal #Female compares as equal), and evaluate to "Adrienne is a girl!". The last clause showcases the wildcard pattern _. It cannot fail, but won’t bind any identifier.

最後のパタンは or パタンです. その名前が示すとおり, 二つ以上のパタンをキーワード or で繋いだものです. サブパタンはそれぞれ, 同じ識別子の集合に束縛しなければならず, 左から右へとマッチさせます. 右端のサブパタンが失敗したときには or パタン全体が失敗します.

The last kind of pattern is the or pattern. As its name suggests, these are two or more patterns that are separated by the keyword or. Each of the sub-patterns must bind to the same set of identifiers, and is matched from left-to-right. An or pattern fails when its rightmost sub-pattern fails.

Untitled

次の表にパタン・マッチングのいろいろな方法をまとめておきます.

The following table summarises the different ways of pattern matching.

Additional information about about patterns

パタン・マッチングには, 豊かな歴史と興味深い機構があるので, それらについて多少コメントを付け加えさせてください.

Since pattern matching has a rich history and interesting mechanics, a few additional comments are justified.

TODO

terminology The (usually structured) expression that is being matched is frequently called the scrutinee and the patterns appearing behind the keyword case are the alternatives. When every possible scrutinee is matched by (at least one) alternative, then we say that the scrutinee is covered. The patterns are tried in top-down fashion and thus in case of overlapping patterns the one higher-up is selected. An alternative is considered dead (or inactive), if for every value that it matches there is higher-up alternative that is also matched.

booleans The data type Bool can be regarded as two disjointed altenatives (true and false) and Motoko’s built-in if construct will eliminate the data and turn it into control flow. if expressions are a form of pattern matching that abbreviates the general switch expression for the special case of boolean scrutinees.

variant patterns Motoko’s variant types are a form of disjoint union (sometimes also called a sum type). A value of variant type always has exactly one discriminator and a payload which can vary from discriminator to discriminator. When matching a variant pattern with a variant value, the discriminators must be the same (in order to select the alternative) and if so, the payload gets exposed for further matching.

enumerated types Other programming languages — for example C, but not Motoko — often use a keyword enum to introduce enumerations. These are impoverished relatives of Motoko’s variant types, as the alternatives are not allowed to carry any payload. Correspondingly, in those languages the switch-like statements lack the full power of pattern matching. Motoko provides the short-hand syntax (as in type Weekday = { #mon; #tue; … }) to define basic enumerations, for which no payloads are required.

error handling Error handling can be considered a use-case for pattern matching. When a function returns a value that has an alternative for success and one for failure (for example, an option value or a variant), pattern matching can be used to distinguish between the two as discussed in Error handling.