Chapter 20 パターンとパターンマッチング
値束縛宣言(valBind)(23.1)の束縛対象および 関数宣言(funDecl)(23.2), case式 (19.18), fn式 (19.19), handle式 (19.14) の引数には,パターンを記述する. 変数はパターンの特殊な場合である.
パターンは,値が持つべき構造を記述する. 記述されたパターンは,対応する値とマッチングが試みられ,マッチす れば,パターンに含まれる変数が,その現れる位置に対応する値に束縛される. パターンマッチングは,各パターンのスコープにある式を評価のた めの束縛環境にパターンに含まれる変数の束縛環境を追加する効果を持つ. 従って,各パターンは,静的な評価の場合,追加すべき型環境を,実行 時の動的な評価の場合,型環境に対応した値の環境を生成する.
pat構文は以下の文法で与えられる.
-
•
パターン(トップレベル)
pat ::= atpat op longVid atpat データ構造 pat vid pat データ構造(演算子表現) pat : ty 型制約パターン vid : ty as pat 多層パターン -
•
原子パターン
atpat ::= scon 定数 _ 匿名パターン vid 変数及びコンストラクタ longVid コンストラクタ {patrow } レコードパターン () unit 型定数 (pat,,pat) 組 () [pat,,pat] リスト () (pat) patrow ::= ...
匿名フィールド lab = pat , patrow レコードフィールド vid:ty as pat ,patrow 変数兼ラベル
以下,各パターンpatについて,その型tyと 生成される型環境およびマッチする値を定義する. 実行時の動的な評価時に生成される環境は,生成される型環境に対応す るマッチした値の束縛環境である.
定数パターン:scon
19.2で定義された定数式同一であり,対応する型を持ち,空 の型環境を生成する. 同一の定数値にマッチする.
匿名パターン:_
文脈に従って決まる任意の型を持ち,空の型環境を生成する. パターンの型を持つ任意の値にマッチする.
識別子パターン:vid
この識別子名が,このパターンが現れる位置をスコープとして含むコン ストラクタとして定義されていれば,そのコンストラクタの型を持ち,空の型環 境を生成する. そのコンストラクタにマッチする.
識別子が定義されていないか,または,変数属性を持つ名前として定義 されていれば,この名前は文脈によって定まる任意の型tyを持ち, 型環境を生成する. 型tyを持つ任意の値にマッチする. このパターンは,パターンを含む構文が定めるスコープ規則に従い,名 前vidが再定義される.
以下に簡単な例を示す.
SML# 4.1.0 (2021-11-08) for x86_64-pc-linux-gnu with LLVM 19.1
# val A = 1
val A = 1 : int
# fn A => 1;
val it = fn : [’a. ’a -> int]
# datatype foo = A;
datatype foo = A
# fn A => 1;
val it = fn : foo -> int
# datatype foo = A of int;
datatype foo = x of int
# fn A => 1;
(interactive):12.3-12.3 Error:
(type inference 039) data constructor A used without argument in pattern
long識別子パターン:longVid
このlong識別子名が,このパターンが現れる位置をスコープとして含む 引数を持たないコンストラクタvidとして定義されていれば, 空の型環境が生成されれ,コンストラクタvidにマッチする. 現在の環境にlong識別子がコンストラクタとして定義されていないか, または,引数を持つコンストラクタとして定義されていれば,エラーとなる. 以下に簡単な例を示す.
# structure A = struct datatype foo = A | B of int val C = 1 end;
structure A =
struct
datatype foo = A | B of int
val C = 1 : int
end
# val f = fn A.A => 1;
val f = fn : A.foo -> int
# val g = fn A.B => 1;
(interactive):3.11-3.13 Error:
(type inference 046) data constructor A.B used without argument in pattern
# val h = fn A.C => 1;
(interactive):4.11-4.13 Error: (name evaluation "020") unbound constructor: A.C
A.Bは引数を持つコンストラクタであり,A.Cは変数であるため, 関数宣言gとhはエラーとなる.
レコードパターン:{patrow }
レコードフィールドパターンpatrowが指定されない {}の形のパターンの場合,空のレコード{}にマッチする. 変数の型環境は生成されない.
レコードフィールドパターンpatrowが指定されている場合, そのフィールド型を lab:ty,, lab:ty, 生成される変数の型環境をとす る. レコードフィールドパターンpatrowの形に応じて以下の2通 りの場合がある.
-
1.
匿名フィールド
...
を含まない固定レコードパターンの場合. フィールド型からなる単相レコード型 {lab:ty,, lab:ty} を持ち,型環境を生成する.このパターンは,レコードフィールドパターンpatrowにマッ チするレコードフィールドを含む上記の型のレコードにマッチする.
-
2.
多相レコードパターン. レコードフィールドパターンpatrowが,匿名フィールド
...
を含む場合. patrowのフィルド型をレコードカインドとしてもつ多相レコード型 ’a#{lab:ty,, lab:ty} を持ち,レコードフィールドパターンpatrowが生成する変数束縛を生 成する. この多相型は,文脈の型制約により,種々の多相レコード型または単相 レコード型にインスタンス化されうる.このパターンは,レコードフィールドパターンpatrowにマッ チするレコードフィールドを含む上記の型のレコードにマッチする.
レコードフィールドパターン:patrow
-
•
匿名フィールドパターン:.... 指定されたフィールド集合が,レコードの一部であることの指定である.
-
•
フィールドパターン:lab = pat , patrow. , patrowのフィールド型を lab:ty,, lab:ty, 型環境を, パターンpatの型をty,生成する型環境をとする.
ラベルlabが lab,,labとすべて異なる場合, フィールド型 lab:ty,lab:ty,, lab:ty, を持ち,型環境が生成される. ラベルlabが lab,,labの何れかと一致する場合は型エラーである.
-
•
変数兼ラベルパターン: vid:ty as pat , patrow.
以下のフィールドパターンに変換された後評価される.
vid = vid:ty as pat , patrow.
生成される型環境,マッチする値は,対応するレコードパターンの場合と同一である. 以下に簡単な例を示す.
# val f = fn {x:int as 1, y} => x + y;
(interactive):33.8-33.34 Warning: match nonexhaustive
{x = x as 1, y = y} => ...
val f = fn : {x: int, y: int} -> int
# val g = fn {x = x:int as 1, y = y} => x + y;
(interactive):34.8-34.37 Warning: match nonexhaustive
{x = x as 1, y = y} => ...
val g = fn : {x: int, y: int} -> int
# f {x = 1, y = 2};
val it = 3 : int
# g {x = 1, y = 2};
val it = 3 : int
組パターン:(pat,,pat)
レコードパターン
{1 = pat, , = pat}
に変換され,評価される. 生成される型環境,マッチする値は,対応するレコードパターンの場合と同一である. 以下に簡単な例を示す.
# val f = fn (x,y) => 2 * x + y;
val f = fn : int * int -> int
# val g = fn {1=x, 2=y} => 2 * x + y;
val g = fn : int * int -> int
# f 1=1, 2=2;
val it = 4 : int
# g (1,2);
val it = 4 : int
リストパターン:[pat,,pat]
ネストしたリストデータ構造パターン
pat :: :: pat :: nil
に変換され,評価される. 生成される型環境,マッチする値は,対応するコンストラクタアプリケー ションパターンの場合と同一である. 以下に簡単な例を示す.
# val f = fn [x,y] => 2 * x + y;
(interactive):24.8-24.26 Warning: match nonexhaustive
:: (x, :: (y, nil )) => ...
val f = fn : int list -> int
# val g = fn (x::y::nil) => 2 * x + y;
(interactive):25.8-25.32 Warning: match nonexhaustive
:: (x, :: (y, nil )) => ...
val g = fn : int list -> int
# f (1::2::nil);
val it = 4 : int
# g [1,2];
val it = 4 : int
データ構造パターン:op longVid atpat
longVidが型ty -> tyを持 つコンストラクタに束縛されている時,型tyを持ち,atpatが生成する型環境を生成する. このパターンは,atpatのマッチするデータを部分構造としてもつデータ構造にマッチする.
演算子表現のデータ構造パターン pat vid patは, op vid(pat,pat)に変換された後評価される. その型と生成される型環境,マッチする動的値は,変換後のパターンと同一である.
型制約パターン: pat:ty
パターンpatが型tyと型環境を持ちかつ tyとtyが型代入のもとで単一化できる場合, 型を持ち,型環境をもつ. 型制約の下で,パターンpatにマッチする値にマッチする.
多層パターン: vid : ty as pat
パターンpat:tyが型tyと型環境をもてば, このパターンは型tyと型環境をもつ. このパターンは,pat:ty にマッチする動的値にマッチする.