時代遅れひとりFizzBuzz祭り Perl編

時代遅れひとりFizzBuzz祭り、今回はPerl。前回がGNU AWKだったので、その流れでテキスト処理用の言語としての地位をAWKから掻っ攫っていったPerlにしてみた。実に安直だ。

Perlは殆ど触ったことがない。時々、拾ったツール*1Perlで書かれてた等の理由でやむを得ずネットの情報を参考にして弄ることはあるけど、基本的に全く分かっていない。

なのでFizzBuzzも試行錯誤しながら書いてみた。ちなみに今更ながらPerl 5.8だ。

#!/usr/bin/perl

use strict;
use warnings;

sub fizzbuzz {
	my ($n) = @_;
	my $val = '';

	$val = 'Fizz' if ($n % 3 == 0);
	$val = $val . 'Buzz' if ($n % 5 == 0);
	$val = $n if ($val eq '');

	return $val;
}

foreach my $i (1..100) {
	print &fizzbuzz($i), "\n";
}

Perlっぽい書き方なのか、そうでないのか不明。実はPerlでサブルーチンを初めて定義した。

偏見かもしれないけど、Perl使いならもっと短いコードを書くと思うので、もう少しだけ短くしてみた。

#!/usr/bin/perl

use strict;
use warnings;

sub fizzbuzz {
	my ($n) = @_;

	my $val = ($n % 3 == 0) ? 'Fizz' : '';
	$val = $val . 'Buzz' if ($n % 5 == 0);

	($val eq '') ? $n : $val;
}

for (1..100) {
	print &fizzbuzz($_), "\n";
}

あまり短くなっていないけど、可読性とか含めて私にはこの辺が限界。

Perlはかなり自由に書けると思う。例えばLisp脳的データ変換な発想が混じったこんなコードとか。

#!/usr/bin/perl

use strict;
use warnings;

sub fizzbuzz {
	my $val = ($_[0] % 3) ? '' : 'Fizz';
	$val = $val . 'Buzz' unless ($_[0] % 5);
	($val eq '') ? $_[0] : $val;
}

map {print "$_\n"} (map {fizzbuzz($_)} (1..100))

……あれ、間違えた。printの結果を更にリストにしてどうする。

改めて、こんなコード。

#!/usr/bin/perl

use strict;
use warnings;

sub fizzbuzz {
	my $val = ($_[0] % 3) ? '' : 'Fizz';
	$val = $val . 'Buzz' unless ($_[0] % 5);
	($val eq '') ? $_[0] : $val;
}

foreach (map {fizzbuzz($_)} (1..100)) {print "$_\n"} 

流石TMTOWTDI

わざわざfizzbuzzを定義する必要も無いので、こうも書ける。

#!/usr/bin/perl

use strict;
use warnings;

foreach (map {
    my $val = ($_ % 3) ? '' : 'Fizz';
    $val = $val . 'Buzz' unless ($_ % 5);
    ($val eq '') ? $_ : $val;
         } (1..100)) {print "$_\n"}

……しかし問題が1つある。インデントや改行のスタイルがこれでよいのか分からない。一応、NTEmacsのデフォルトの設定でインデントしたらこうなった。

さて、ここで後学の為にPerl組み込みのデータ構造のうち、リストを触ってみることにした。まずは配列から。

#!/usr/bin/perl

use strict;
use warnings;

sub fizzbuzz {
	my ($n) = @_;
	my @ref_tbl = ($n, 'Fizz', 'Buzz', 'FizzBuzz');
	my $fizz = ($n % 3 == 0) ? 1 : 0;
	my $buzz = ($n % 5 == 0) ? 2 : 0;

	return $ref_tbl[$fizz + $buzz];
}

for (1..100) {
	print &fizzbuzz($_), "\n";
}

そしてハッシュ。ハッシュにする意味はないけど、取り敢えず書いてみた。

#!/usr/bin/perl

use strict;
use warnings;

sub fizzbuzz {
	my ($n) = @_;
	my %ref_tbl = (
		0 => $n,
		1 => 'Fizz',
		2 => 'Buzz',
		3 => 'FizzBuzz'
	);
	my $fizz = ($n % 3 == 0) ? 1 : 0;
	my $buzz = ($n % 5 == 0) ? 2 : 0;

	return $ref_tbl{$fizz + $buzz};
}

for (1..100) {
	print &fizzbuzz($_), "\n";
}

分かりやすさ優先で「=>」を使っている。

Perlユーザの私から見て、PerlC言語系っぽく、sedっぽく、AWKっぽく、シェルスクリプトっぽく、Rubyっぽく*2、しかしどうしようもなくPerl的だ。今後使うかどうかは……$、@、%、&の記号の使い分けやコンテキストに悩まない程度にPerlに慣れない限り、短気な私には厳しいと思う*3

*1:id:eel3:20090326:1238028836のgccr.plとか。

*2:正確には、RubyPerlから色々なものを引き継いでいるのだけど。

*3:慣れれば嬉々として使うかもしれないけど。