プログラミング言語SML#解説 3.7.1版
19 式

19.10 関数適用式 ⟨appexp⟩ ⟨atexp⟩

以上に定義した原子式は,構文自体に式の区切りを含んいる式の最小単位 である. 式はこの原子式を式構成子によって組み合わせて構成されている. 組み合わせの中で最も結合力が強い式構成子が,関数適用である. ラムダ式の伝統を引き継ぐSML#では,関数適用は,文法 ⟨appexp⟩ ⟨atexp⟩ に示すように,関数を表す式⟨appexp⟩と引数を表す式⟨atexp⟩ を単に式を並べて記述する. ⟨exp1⟩ ⟨exp1⟩ ⟨exp3⟩のように連続して 並べられた式は,この文法から,左結合する関数適用のネスト ((⟨exp1⟩ ⟨exp1⟩) ⟨exp3⟩) と解釈される.

関数適用式⟨appexp⟩ ⟨atexp⟩の評価は以下のように行われる.

  1. 1.

    式⟨appexp⟩を静的に評価し,型を求める. もし型が関数型⟨ty1⟩ -> ⟨ty2⟩でなければ, 型エラーとなる.

  2. 2.

    式⟨atexp⟩を静的に評価し,⟨ty3⟩型を求める. ⟨ty1⟩と⟨ty3⟩が同一でなければ型エラーとなる.

  3. 3.

    式⟨appexp⟩を動的に評価し,値Clsを求める. 値は関数クロージャである.

  4. 4.

    式⟨atexp⟩を動的に評価し,値vを求める. 関数クロージャClsに保存された環境に,仮引数の値vへの束縛を追加し, その環境の下で,関数クロージャClsに保存されたコードを実行し,動的な値v′を求める. 型⟨ty2⟩とv′が,関数適用式の型と値である.

以下に関数適用式を含む例を示す. 最後の例では,#name f("joe", 21)は ((#name f) ("joe", 21))と解釈され,型エラーとなる.

# val f = fn x => fn y => fn z => (x,y,z);;
val f = fn : [’a. ’a -> [’b. ’b -> [’c. ’c -> ’a * ’b * ’c]]]
# f 1 2 (3,4);
val it = (1,2,(3,4)) : int * int * (int * int)
# fun f (x,y) = {name=x,age=y};
val f = fn : [’a, ’b. ’a * ’b -> age: ’b, name: ’a]
# #name (f ("joe", 21));
val it = "joe" : string
# #name f("joe", 21);
(interactive):5.0-5.6 Error:
(type inference 028) operator and operand don’t agree
operator domain: ’BCUJ#{name: ’BCUI}
          operand: [’a, ’b. ’a * ’b -> {age: ’b, name: ’a}]