アキュムレータ(ハッカーと画家(ISBN:4274065979)より)

付録:力(P198)

私が言う言語の相対的な力を説明するために、次の問題を考えてみよう。アキュムレータを生成する関数、すなわち。数nを取り、「数iを取ってnをiだけ増加させ、その増加した値を返す関数」を返すような関数だ(「増加させる」に注意。ただ足すだけではない。アキュムレータ(累積器)だから累積させなければ)。

とあって、LispRubyPerlのプログラムが載っていた。ちょうどPerlの勉強中なので掲載されていた(たった4行の)プログラムについて考えてみた。

sub foo {
	my ($n) = @_;
	sub {$n += shift}
}

初心者全開なので見ただけじゃわからない。これを使うために以下のプログラムを書いた。

#!c:\perl\bin
use strict;
my $accumulator = foo(shift); #第一引数が初期値(数n)となる
while ($_ = shift) {
	print &$accumulator($_);
	print "\n";
}

sub foo {
	my ($n) = @_;
	sub {$n += shift}
}

小一時間くらいいじくってようやく合点した。
例えば実行結果は以下のようになる(ファイル名はさておき汗)。

C:\Temp>hacker1.pl 0 1 2 3 4 5 6 7 8 9 10
1
3
6
10
15
21
28
36
45
55

ポイントは、

  1. fooの一行目はリストコンテキストで代入が行われるので引数の一番目が$nに代入される。
  2. fooの戻り値は引数の先頭から値を一つ取り出して$nに足すサブルーチン(名前はまだない)。
  3. fooの戻り値はサブルーチンなのでそのままprintするとCODE(0x274ef0)なんかが表示される
  4. fooの戻り値であるサブルーチンを変数に代入し、実行時はサブルーチンであることを明示的に示すために先頭に&を付ける

こんなところかな。
Cだとどうすんのかな。関数ポインタとstatic変数使えばできる?のか?(また今度暇なときに考えよ)