F# 勉強中。
命令型言語に宣言型 (関数型言語) の考え方を持ち込むのと、関数型言語 (宣言型) に命令型の考え方を持ち込むのでは、基本が異なる。その基本となる違いを自分なりにメモ。
変数の捉え方
代入 (substitution) と束縛 (binding) の違い
命令型における代入
代入 (substitution) とは、例えば JavaScript であれば以下のように書く:
var x = 100;
これは、x
という変数の箱に、100
という値を入れておく「箱モデル」。主従関係は、主が変数 x
であり、従が値 100
であるという捉え方。
変数 x
という箱には、いくらでも新しい値を代入可能。これを破壊的代入と呼ぶ。
宣言型における束縛
束縛 (binding) とは、例えば F# であれば以下のように書く:
let x = 100;;
これは、100
という値に、x
というラベルを貼り付ける「名札モデル」。主従関係は、主が値 100
であり、従が変数 x
であるという捉え方。
値 100
には、変数 x
という名札が束縛されており、この値を呼び出すための一意の識別子として変数 x
が存在している。これは不変 (= immutable) な関係であり、お互いの関係をすげ替える事はできない。
シャドウイング
宣言型において変数と値は不変な関係を持つと言われると、次のような行為が不可能なように思われる:
let x = 100;;
let x = 1;;
変数 x
に値 100
が束縛された後、変数 x
に値 1
を束縛している。これは不正ではなくシャドウイング (shadowing) と呼ばれる捉え方で解釈する。
値 100
も値 1
も不変な存在であるため、変数に x
に束縛される前も後も、その存在は不変である。ただそれらにアクセスするための識別子である変数 x
という名札がどのように機能するか、そのルールを知れば良い。
シャドウイングというルールにおいては、もっとも後で、束縛されたものが優先される。
つまりこの場合は;
let x = 1;;
が優先される束縛となる。故に変数 x
を参照すると、値 1
が得られる事となる。
高階関数
カリー化
F# において関数への複数引数の適用は、カリー化と同一である。
長方形の面積を求める関数 areaOfRectangle
について考える:
let areaOfRectangle w h = w * h
上の関数と下の関数は同義となる:
let areaOfRectangle = fun w h -> w * h
let areaOfRectangle = (fun w -> (fun h -> w * h))
let areaOfRectangle w = fun h -> w * h
部分適用
この関数を次のように部分適用してやる事が可能:
let areaOfRectangleWithWidth5 = areaOfRectangle 5
次の 2 つの関数は同じ値 50
を返す:
> areaOfRectangle 5 10 = areaOfRectangleWithWidth5 10;;
val it : bool = true
引数の順番
部分適用を重視し、先に適用できるものがあるとすればそれは何か、最後までその決定を引き延ばしたいものは何かを考えるのです。 [...]
[...] 付加的な情報を先に与えておいて、最も重要な情報はパイプライン演算子によって最後に流し込むのです。