23.1 val宣言 : valDecl
val宣言の構文は,以下の文法で定義される.
valDecl | ::= | val tyvarSeq valBind |
valBind | ::= | valBind1 |
valBind1 and valBind | ||
valBind1 | ::= | pat = exp |
この宣言では,andで接続された複数の宣言に含まれる変数が同 時に束縛される. 束縛された変数の有効範囲は,この宣言と同一のスコープを持つこの宣 言に続く部分である. 各patに現れる変数はすべて異なっていなければならない.
valDeclのtyvarSeqは,valBindに現れる型変数 のスコープの指定である. これら型変数は,各valBind1のトップレベルで型抽象される.
23.1.1 val宣言インタフェイス : valSpec
val宣言のインターフェイスは,束縛される変数それぞれについて, とその型を以下の形で宣言する.
valSpec | ::= | val id : ty |
例えば,val 宣言
val (x,y) = (1,2)
に対するval宣言インターフェイスは以下の2つのインターフェイス宣言である.
val x : int
val y : int
23.1.2 val宣言の評価
値束縛宣言
val pat = exp and pat = exp
の評価は,構造パターンの評価と式の評価の2段階で行われる.
構造パターン評価
構造パターンを含む値束縛は,まず,パターン集合に含まれる変数集合 に対する値束縛に変換される.
パターン集合に定数やコンストラクタパターンが一つも含まれない場合, この変換は以下の手順で行われる.
-
1.
パターンpatと式expの組が,再帰的に, 部分パターンと部分式の組みの集合に分解される.
-
2.
各パターンpatが,その構造に従い,部分パターンの組 に分解される. この時,patが型制約を持てば,分解された部分パター ンにも型制約が付加される.
-
3.
式の分解は,上記ステップで分解された部分パターンに対して,対応す る部分を取り出す操作を,式expに対して静的に実行することに よって行う. すなわち,式が構造式の場合は,部分式が取り出され,式が構造式でな い場合は,式を変数に束縛し,構造から部分構造を取り出す関数を変数に適用す る式が生成される.
-
4.
パターンが as の形の階層パターンを 含む場合,上記 の操作に加えて,に対して構造全体の値が静的に生成される.
-
5.
以上生成された変数と式の組の集合が,
val =
and =の形の変数束縛宣言として生成される.
以下の23.1.3で示すように,以上のように パターンによる値束縛宣言を,可能な限り変数の束縛に変換することにより, Bind例外を起こさない値束縛において,SML#が推論する式のランク1多 相型を変数の型として引き継ぐことが可能となる.
パターン集合に定数やコンストラクタパターンが含まれる場合,構造を 含む値束縛は,実行時に例外を発生することがあり,静的な評価をすることがで きない. この場合は,与えられた値束縛が以下の形の変数束縛に変換される.
val = case (exp, , exp) of
(pat, , pat) => (,,)
| _ => raise Bind
val = #1
and = #
以上の変換により,値束縛宣言に含まれる変数集合の式への同時束縛宣 言が作られる.
23.1.3 val宣言とインタフェイスの例
以下は,ランク1多相性を含む型束縛の例である.
# val (x,y) = (print "SML#
\
n", fn x => fn y => (x,y));
SML#
val x = () : unit
val y = fn : [’a. ’a -> [’b. ’b -> ’a * ’b]]
このように,変数には式の持ちうるランク1多相が与えられる. この評価方式は,上例のように式の一部に副作用を持つ場合でも,安全 である. 以下の例のように,パターンがコンストラクタや定数を含む場合は,こ の値束縛構文自体が副作用を含む可能性があるため,変数への多相型は与えられない.
# val (x,y, 1) = (print "SML#
\
n", fn x => fn y => (x,y), 1);
(interactive):2.8-2.8 Warning:
(type inference 065) dummy type variable(s) are introduced due to value
restriction in: y
(interactive):2.4-2.57 Warning: binding not exhaustive
(x, y, 1) => ...
SML#
val x = () : unit
val y = fn : fn : ?X7 -> ?X6 -> ?X7 * ?X6
以下は,ソースファイルとインターフェイスファイルの簡単な例である.
Version.sml file:
val (version, releaseDate) = ("3.7.1", "2021-03-15")
Version.smi file: val version : string val releaseDate : string |