Haskell-クロージャ
クロージャ(Closure)について
一般的なクロージャ
クロージャとは、その関数が定義された環境(変数及びスコープ)への参照を持った関数のことです。
クロージャは英語で「閉鎖」という意味です。
(実際には、クロージャの概念自体が言語によって定義が異なります。)
Haskellにおけるクロージャ
Haskellは純粋関数型言語であるため、JavaScriptなどのクロージャと違い、変数(再束縛)がありません。
そのため、関数から無名関数を返す際に無名関数の外側の値を束縛することがHaskellにおけるクロージャといえます。
さらに広義にとらえれば、関数内で一時的な関数を生成してそれを戻り値とするような「関数を返す関数」をクロージャといえます。
(実際には「無名関数の部分適用」と類似した機能といえます。)
レキシカルスコープ(lexical scope)とは
レキシカルスコープとは、構文の構造のみから決定できるため構文スコープのことです。
変数や式のスコープが構文から判断できるのでレキシカル(lexical)と呼ばれます。
クロージャはレキシカルスコープを保持し、これを扱います。
レキシカルスコープは、静的スコープ(static scope)とも呼ばれます。
なお、対義語が動的スコープ(dynamic scope)です。
クロージャへの式変形
加算する関数をクロージャに変形します。
変形1 通常の関数記述
2つの引数をとり、値を返す関数です。
#!/usr/bin/env runghc
add :: Integer -> Integer -> Integer
add x y = x + y
main = print(add 5 2)
変形2 クロージャ化1
fはadd(エンクロージャ)の中で定義された一時的な関数(クロージャ)となります。
クロージャ(f)からはエンクロージャの値(xとy)を参照することとなります。
#!/usr/bin/env runghc
add :: Integer -> Integer -> Integer
add x y = f
where f = x + y
main = print(add 5 2)
変形3 クロージャ化2
引数付きの関数としてfを定義します。
#!/usr/bin/env runghc
add :: Integer -> Integer -> Integer
add x y = f x y
where f a b = a + b
main = print(add 5 2)
変形4 部分適用にする
定義の中で外側の引数xを使用するように部分適用します。
#!/usr/bin/env runghc
add :: Integer -> (Integer -> Integer)
add x = f
where
f :: Integer -> Integer
f y = x + y
main = print((add 5) 2)
変形5 無名関数にする
add関数の中で引数yを取る無名関数を返すようにします。
#!/usr/bin/env runghc
add :: Integer -> (Integer -> Integer)
add x = (\y -> x + y)
main = print((add 5) 2)