2010/03/04

PowerShell 2.0ではscriptblockにGetNewClosure()メソッドが追加され、クロージャを記述することができるようになりました。

クロージャを作るには、まず関数の中に変数(レキシカル変数)と関数(PowerShellではスクリプトブロック)を定義します。外側の関数内に定義された変数(レキシカル変数)を関数内に定義された内側の関数から操作するようにしておきます。そして外側の関数は内側の関数そのものを返却するようにしておきます。これでクロージャができました。

クロージャを使用するには、まず外部から外側の関数の戻り値(これは内側の関数です)を変数に代入します。そしてこの変数に含まれる関数(内側の関数)を実行すると、レキシカル変数に何らかの変化を及ぼしつつ結果が返却されます。ポイントは、レキシカル変数の値が保持されることです。その結果、内側の関数を実行するたびにその時のレキシカル変数の値に基づいた結果を返却するようにできるわけです。

とまあ書いても何のことかよくわからないかと思いますので実例を示します。よくある例題なのですが、「呼び出すたびに1が加算された結果を返す関数。すなわち、呼び出すと結果が、1,2,3,4…と続いていく関数」を考えます。

function counter()
{
	$x=0
	return {$script:x++;return $x}.GetNewClosure()
}

これがクロージャの本体です。ポイントは、scriptスコープを使用することで内側のスクリプトブロックからレキシカル変数(ここでは$x)の値を変更している点です。

使用法は次のようになります。変数$fにcounter関数の内側のスクリプトブロックを代入し、&演算子で実行しています。

PS C:\Users\daisuke> $f=counter
PS C:\Users\daisuke> &$f
1
PS C:\Users\daisuke> &$f
2
PS C:\Users\daisuke> &$f
3
PS C:\Users\daisuke> &$f
4
PS C:\Users\daisuke>

見事、お題を実現することができました。

さて、GetNewClosure()メソッドが追加されたことで、関数のカリー化も可能になります。カリー化とは、たとえばf(x,y)という関数があった場合、g(x)(y)という、f(x,y)と常に同じ値を返却する関数を作ることです。一般には、複数の引数をとる関数fを、fの最初の引数だけを引数にとり、「fの残りの引数をとり結果を返す関数」が戻り値であるgという関数に変換することです。これまた何のことかわかりにくいですね。

たとえば一番簡単な例。引数同士を加算する関数sumをカリー化してcurried_sumという関数を作ってみます。

function sum([int]$x,[int]$y)
{
	return [int]($x+$y)
}

function curried_sum([int]$x)
{
	return {param([int]$y);return sum $x $y}.GetNewClosure()
}

これでsumのカリー化ができました。実行してみます。

PS C:\Users\daisuke> &$(curried_sum 3) 4
7
PS C:\Users\daisuke> &$(curried_sum -6) 14
8
PS C:\Users\daisuke> &$(curried_sum -2) -3
-5
PS C:\Users\daisuke> $sum5 = curried_sum 5
PS C:\Users\daisuke> &$sum5 11
16
PS C:\Users\daisuke> &$sum5 -4
1
PS C:\Users\daisuke> $sum2 = curried_sum 2
PS C:\Users\daisuke> &$sum2 8
10
PS C:\Users\daisuke> &$sum2 1
3

PowerShellの関数の呼び出し方がわりと特殊であるため、少々分かりにくいですがサブ式$()と呼び出し演算子&をつかってカリー化されたsum関数を実行して目的通りの結果を得ています。たとえば最初の例は3+4を実行していることになり、結果はsum 3 4と同じ7になります。以下同様です。$sum5は、「引数に5を加える関数」になります。

いかがでしたでしょうか。PowerShellでも(なんか文法とか奇妙ですが)クロージャやカリー化ができて楽しいですね。というか私は本記事を書くにあたってクロージャとカリー化がなんぞやということを勉強しました…。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2010/03/04/186768.aspx

古い記事へ | 新しい記事へ


プライバシーポリシー

Twitter

Books