スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

F#入門第9回(引数が2個以上の関数と関数の部分適用)

今日のお題は「引数が2個以上の関数と関数の部分適用です」です。

宿題の解答
(1)float型の引数を1個受け取って、その数を5倍した数を返す関数mul5を二通りの書き方で書いてください。
答えは次の通りです。
let mul5 = fun x -> 5.0 * x
let mul5 x = 5.0 * x

(2)int型の引数kを1個受け取って「引数よりkだけ大きい数を返す関数」を返す関数plusCを二通りの書き方で書いてください。またこの関数plusCの型を書いてください。
引数kを受け取ったときに、関数(fun x -> x + k)を返せばよいのですから
let plusC = (fun (k : int) -> (fun x -> x + k)) または
let plusC (k : int) = (fun x -> x + k)
となります。
普通に考えるとこの関数の型はint -> (int -> int) ですが、F#Interactiveではint -> int -> intと表示されます。これのなぞ解きは、今日の後半部分のお題です。
ところでこの関数を5に適用した値にplus5という名前を付けてみます。

> let plusC (k : int) = (fun x -> x + k);;
val plusC : int -> int -> int

> let plus5 = plusC 5;;
val plus5 : (int -> int)

plusCは引数kを1個受け取って「引数よりkだけ大きい数を返す関数」でしたから、これを5に適用した値は「引数より5だけ大きい数を返す関数」です。これにplus5と名前を付けたのですから、例えばplus5 6 とすれば11が返ってくるはずです。実験してみます。

> plus5 6;;
val it : int = 11

と予想通りに動きました。

さて本題に入ります。
引数が2個以上の関数ですが、例えば次のように定義します。(引数全体は括弧でくるまれないし、引数の間にカンマも書かないことに注意!)

fun x y -> x - y

名前をsubt にすると

let subt = (fun x y -> x - y)

です。
これも、引数が一つのときと同様に略記法があり、次のようにします。

let subt x y = x - y

これらで、引数が2つで、第一引数から、第二引数を引いた値を返す関数subtが定義できました。
F#Interactiveで試してみます。

> let subt x y = x - y;;
val subt : int -> int -> int

実際の数に適用するには、関数名の後に引数を並べます。

> subt 3 9;;
val it : int = -6

ところでsubtの型がint -> int -> intとなってますが、これはデフォルトでは、足し算とか引き算では、int型に型推論されるからで、型注釈をつけるか、型推論のネタを提供すれば他の型同士にも使えます。
例えば

> (fun x y -> x - y) 3L 10L;;
val it : int64 = -7L

となります。

さて、この関数subtを一つの引数だけに適用すると、どうなるでしょうか。
(普通に考えるとエラーがでそうなものです。)
実際に10に適用して、その適用した値にsubtf10と名前を付けてみます。

> let subtf10 = subt 10;;
val subtf10 : (int -> int)

なんと、int -> int の関数が返ってきました。
これはlet subt x y = x y のxを10に固定したもので、引数を一つとって、10からその引数を引いた値を返す関数なのです。
このように、複数の引数をもつ関数に、第1引数や(第1引数と第2引数)というように、左からいくつかの引数を与えると、元の関数の引数のうちの最初の何個かを固定した関数を返します。
このように、複数の引数をもつ関数に、最初のいくつかの引数だけを与えて、関数を得ることを、「関数の部分適用」といいます。

> let mulp x y = x * y;;
val mulp : int -> int -> int

次にxを3に固定した関数をmulp3として定義します。

> let mulp3 = mulp 3;;
val mulp3 : (int -> int)

mulp3を5に適用します。(もちろん3倍されて15が返ってくるはずです。)

> mulp3 5;;
val it : int = 15

さて、次はmulp の型がint -> int -> int であることの説明です。
例えばint -> int 型の関数に3を渡すと,intが返ってきます。図で表すと
int -> int
3 返り値
となります。
mulpに3と5を渡すとintが返ってきます。図で表すと
int -> int -> int
3 5
つまり、具体的に渡した引数以外の部分が返ってくるわけです。
それではmulpに3を渡すと、図でどうなるかというと
int -> int -> int
3 ( 返り値 )
つまり残りのint -> int が返り値すなわち、int型からint型への関数が返るわけです。
うまくできているものです。

ということで、関数の型を見れば、引数を何個与えれば、どういう値(関数含む)が返ってくるか、すぐわかるようにできているのです。

宿題の関数はlet plusC (k : int) = (fun x -> x + k) と定義されていて型はint -> int -> intでしたが、引数一つだけ与えるると(3にしてみます)plusC 3で「3大きい数を返すint -> int 型の値(関数)」を返しますし、引数を二つ与えると、例えばplusC 3 4 は(plusC 3) 4と解釈され、3大きい数を返す関数を4に適用するということで7というint型の値を返します。きちんと上のルールを満たしています。

それではまとめです。
複数個の引数をとる関数は
fun x y z -> x + y + z というように、定義する。
名前をつけるには
let sum3 = (fun x y z -> x + y + z) とlet構文を使う。
名づけと定義を一緒にするには
let sum x y z = x + y + z のようにする。
複数個の引数をとる関数に、最初のいくつかの値を具体的に与えることにより、最初のいくつかの引数の値が固定された関数を得ることができる。
これを関数の部分適用という。部分適用の結果どのような型の関数が返るかは、もとの関数の型を見ればすぐ推論することができる。

宿題 int -> int -> int -> int ->int  型の関数を何個のint型の引数に適用すれば、int -> int 型の関数が返り値となるでしょうか。
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

Author:T GYOUTEN
F#と英単語とフリーソフトと読書に興味があります。
ホームページでフリーソフトも公開しています。どぞ御贔屓に。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
フリーエリア
フリーエリア
blogram投票ボタン
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。