19.10 関数適用式 appexp atexp
以上に定義した原子式は,構文自体に式の区切りを含んいる式の最小単位 である. 式はこの原子式を式構成子によって組み合わせて構成されている. 組み合わせの中で最も結合力が強い式構成子が,関数適用である. ラムダ式の伝統を引き継ぐSML#では,関数適用は,文法 appexp atexp に示すように,関数を表す式appexpと引数を表す式atexp を単に式を並べて記述する. exp1 exp1 exp3のように連続して 並べられた式は,この文法から,左結合する関数適用のネスト ((exp1 exp1) exp3) と解釈される.
関数適用式appexp atexpの評価は以下のように行われる.
-
1.
式appexpを静的に評価し,型を求める. もし型が関数型ty -> tyでなければ, 型エラーとなる.
-
2.
式atexpを静的に評価し,ty型を求める. tyとtyが同一でなければ型エラーとなる.
-
3.
式appexpを動的に評価し,値を求める. 値は関数クロージャである.
-
4.
式atexpを動的に評価し,値を求める. 関数クロージャに保存された環境に,仮引数の値への束縛を追加し, その環境の下で,関数クロージャに保存されたコードを実行し,動的な値を求める. 型tyとが,関数適用式の型と値である.
以下に関数適用式を含む例を示す. 最後の例では,#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}]