Perlで継続

現在、『On Lisp』が3巡目の終盤に差し掛かっている。でも、いまいち継続を理解できていない。分かり易い解説を見つけたのでPerlに翻訳してみた。(本を読む FizzBuzzとGaucheで学ぶ継続の基礎)

use strict;
use warnings;

sub fizzbuzz {
  my ($next, ($n)) = @_;
  my $answer = $n % 15 == 0 ? "FizzBuzz"
             : $n %  3 == 0 ? "Fizz"
             : $n %  5 == 0 ? "Buzz"
             : $n;

  # $nextを挟んで再帰呼び出し
  $next->(\&fizzbuzz, ($n + 1, $answer));
}

sub continuation {
  my ($next, ($n, $answer)) = @_;

  # 状態を閉じ込めた状態で関数終了
  my $cc = sub {
    my ($fun) = @_;
    $fun->($answer) if (ref $fun eq 'CODE');
    $next->(\&continuation, ($n));
  };
}

# 1〜100のfizzbuzz継続を生成してリストに保存
my @restart = fizzbuzz(\&continuation, (1));
push @restart, $restart[$#restart]->() for 2..100;

# 1〜100のfizzbuzz継続を実行
$restart[$_]->( sub{ print @_, $_ != $#restart ? '|' : '' } ) for 0..$#restart;

100までのFizzBuzzが表示される。

1|2|Fizz|4|Buzz|Fizz|7|8|Fizz|Buzz|11|Fizz|13|14|FizzBuzz|16|17|Fizz|19|Buzz|Fiz
z|22|23|Fizz|Buzz|26|Fizz|28|29|FizzBuzz|31|32|Fizz|34|Buzz|Fizz|37|38|Fizz|Buzz
|41|Fizz|43|44|FizzBuzz|46|47|Fizz|49|Buzz|Fizz|52|53|Fizz|Buzz|56|Fizz|58|59|Fi
zzBuzz|61|62|Fizz|64|Buzz|Fizz|67|68|Fizz|Buzz|71|Fizz|73|74|FizzBuzz|76|77|Fizz
|79|Buzz|Fizz|82|83|Fizz|Buzz|86|Fizz|88|89|FizzBuzz|91|92|Fizz|94|Buzz|Fizz|97|
98|Fizz|Buzz
  1. fizzbuzz関数からcontinuation関数が呼ばれる。continuation関数はfizzbuzz関数を呼び出す関数を返す。
  2. ↑が返した関数を呼び出すとfizzbuzz関数が呼ばれる。fizzbuzz関数からcontinuation関数が呼ばれ、fizzbuzz関数を呼び出す関数を返す。
  3. 以下、同じことの繰り返し。
# 90のfizzbuzz
print "90 = "; $restart[90-1]->( sub { print @_, "\n" } );

#  4のfizzbuzz
print "4  = "; $restart[4 -1]->( sub { print @_, "\n" } );

# 70のfizzbuzz
print "70 = "; $restart[70-1]->( sub { print @_, "\n" } );

保存してある継続を使って指定した数値のFizzBuzzを表示することもできる。

90 = FizzBuzz
4  = 4
70 = Buzz

分かったような分からないような・・・
修行が足りない。