プログラミング言語SML#解説 3.7.1版
23 核言語の宣言とインターフェイス

23.1 val宣言 : valDecl

val宣言の構文は,以下の文法で定義される.

valDecl ::= val tyvarSeq valBind
valBind ::= valBind1
 | valBind1 and valBind
valBind1 ::= pat = exp

この宣言では,andで接続された複数の宣言に含まれる変数が同 時に束縛される. 束縛された変数の有効範囲は,この宣言と同一のスコープを持つこの宣 言に続く部分である. 各patに現れる変数はすべて異なっていなければならない.

valDecltyvarSeqは,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 pat1 = exp1  and pat2 = exp2

の評価は,構造パターンの評価と式の評価の2段階で行われる.

構造パターン評価

構造パターンを含む値束縛は,まず,パターン集合に含まれる変数集合 {x1,,xm}に対する値束縛に変換される.

パターン集合に定数やコンストラクタパターンが一つも含まれない場合, この変換は以下の手順で行われる.

  1. 1.

    パターンpatiと式expiの組が,再帰的に, 部分パターンと部分式の組みの集合に分解される.

  2. 2.

    各パターンpatiが,その構造に従い,部分パターンの組 に分解される. この時,patiが型制約を持てば,分解された部分パター ンにも型制約が付加される.

  3. 3.

    式の分解は,上記ステップで分解された部分パターンに対して,対応す る部分を取り出す操作を,式expiに対して静的に実行することに よって行う. すなわち,式が構造式の場合は,部分式が取り出され,式が構造式でな い場合は,式を変数に束縛し,構造から部分構造を取り出す関数を変数に適用す る式が生成される.

  4. 4.

    パターンがid as patの形の階層パターンを 含む場合,上記 の操作に加えて,idに対して構造全体の値が静的に生成される.

  5. 5.

    以上生成された変数と式の組の集合が,

    val x1 (:τ1)? = exp1
      
    and xm (:τm)? = expm

    の形の変数束縛宣言として生成される.

以下の23.1.3で示すように,以上のように パターンによる値束縛宣言を,可能な限り変数の束縛に変換することにより, Bind例外を起こさない値束縛において,SML#が推論する式のランク1多 相型を変数の型として引き継ぐことが可能となる.

パターン集合に定数やコンストラクタパターンが含まれる場合,構造を 含む値束縛は,実行時に例外を発生することがあり,静的な評価をすることがで きない. この場合は,与えられた値束縛が以下の形の変数束縛に変換される.

val X = case (exp1, , expn) of
          (
pat1, , patn) => (x1,,xm)
        | _ => raise Bind
val x1 = #1 X
  
and xm = #m X

以上の変換により,値束縛宣言に含まれる変数集合の式への同時束縛宣 言が作られる.

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