Perlで遅延評価

遅延評価とは、HaskellD言語なんかにある「アレ」のことだ。

遅延評価(ちえんひょうか、lazy evaluation、delayed evaluation)とは、計算機科学におけるプログラムの評価手法の一つ。主に関数型言語で使用される。対義語は先行評価(eager evaluation、strict evaluation)。

評価しなければならない値が存在するとき、実際の計算を値が必要になるまで行わないことをいう。評価法が指示されているが実際の計算が行われていない中間状態の時それをプロミス (promise) や、計算の実体をさしてサンク (thunk) といい、プロミスを強制(force)することで値が計算される。一旦計算された値はキャッシュをすることが可能であり、遅延プロミスは最大で一度しか計算されないようにすることができる。ただし、Haskellの実装によっては、何度でも同じ計算を行う。

http://ja.wikipedia.org/wiki/%E9%81%85%E5%BB%B6%E8%A9%95%E4%BE%A1

要するに式の評価を結果が必要になる時点まで遅らせるテクニックである。
Perlでやってみた。定番のFizzBuzz

use strict;
use warnings;

# 整数の無限リスト(1, 2, 3, 4, …)
my $infinite_list = sub { my $c = 1; sub { $c++; } };

# FizzBuzzの無限リスト(1, 2, Fizz, 4, …)
my $fizzbuzz_list = sub {
  my $num_list = $infinite_list->();
  sub {
    my $n = $num_list->();
    if    ($n % (3 * 5) == 0) {"FizzBuzz"}
    elsif ($n % 3  == 0)      {"Fizz"}
    elsif ($n % 5  == 0)      {"Buzz"}
    else                      {$n}
  };
};

# 指定番目までのFizzBuzzを表示
my $print_fizzbuzz = sub {
  my ($n) = @_;
  my $fb = $fizzbuzz_list->();

  # 無限リストが評価されるのは$fbの実行回数だけ
  print $fb->(), $_ != $n ? '|' : '' for (1..$n);
};

# とりあえず100番目までFizzBuzzを表示してみる。
$print_fizzbuzz->(100);

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

無限リストを扱うときに便利だ。