Rでクロージャを使ってみます。
例:アキュムレータを生成する関数
試しにPaul Grahamのエッセイ、Revenge of the Nerds に出てくる「アキュムレータを生成する関数」を書いてみます。
Schemeならこんな感じ。
gosh> (define (make-accumulator n) (lambda (i) (set! n (+ n i)) n)) make-accumulator gosh> (define A (make-accumulator 5)) A gosh> (A 10) 15 gosh> (A 10) 25
Perl5だと
$ perl -de0 Loading DB routines from perl5db.pl version 1.33 Editor support available. Enter h or `h h' for help, or `man perldebug' for more help. main::(-e:1): 0 DB<1> sub make_accumulator { \ cont: my $n = shift; \ cont: sub { $n += shift } \ cont: } DB<2> $a = make_accumulator 5 DB<3> p $a->(10) 15 DB<4> p $a->(10) 25
(他の言語での実装はこちらを参照。)
これをRで書くと
> makeAccumulator <- function(n) { + function(i) { + n <<- n + i + n + } + } > a <- makeAccumulator(5) > a(10) [1] 15 > a(10) [1] 25
短く書くとこんな感じでしょうか。
makeAccumulator <- function(n) function(i) (n <<- n + i)
スーパーアサインメント演算子 <<-
ポイントはスーパーアサインメント演算子 <<-
です。
通常の代入演算子 <-
は同じ環境の変数に代入します。
<<-
は入れ子になった環境を順に外側に検索し、最初に変数の定義が見つかった環境に代入します。
見つからなかった場合はグローバル環境に代入します。
詳細は help(<<-)
を実行してみてください。
今回の例では、内側の関数から、外側の関数の環境の n
に代入したいので、 <-
ではなく <<-
を使う必要があります。