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 に代入したいので、 <- ではなく <<- を使う必要があります。
0 件のコメント:
コメントを投稿