2011年5月18日
2011年5月15日
Perl 5.14.0がリリースされましたね
追記1
リリースノートの翻訳はここで読めます。
http://perldoc.jp/docs/perl/5.14.0/perl5140delta.pod追記2
インストールはperlbrewを使っていればすぐですね。
$ perlbrew install perl-5.14.0
$ perlbrew switch perl-5.14.0
追記3
Perl 5.14対応の「Learning Perl」は7月発売。でも日本語訳はいつになるんでしょうね。
![]() | Learning Perl Randal L. Schwartz Brian D. Foy Tom Phoenix Oreilly & Associates Inc 2011-07-22 売り上げランキング : 190860 Amazonで詳しく見る by G-Tools |
2011年5月 4日
名前をつけてやる
型グロブを使えば無名サブルーチンへ名前を付けることができる。
#!/usr/bin/env perl
package Package_Name;
use strict;
use warnings;
use utf8;
sub create_sub {
my $arg = shift;
my $code = sub {
return $arg;
};
no strict 'refs';
*{"new_subroutine"} = $code;
}
package main;
Package_Name::create_sub('test_message');
my $value = &Package_Name::new_subroutine;
print "$value\n";
コンパイルのタイミングには存在しない名前なので、&を付けるか、->()を付けて関数の名前である事を明示しないといけないっぽい。
もう少し自分の中で整理しないと、分からない事だらけだ。
あ、あと「名前をつけてやる」と言えばスピッツの古いアルバムのタイトルだけど、こんなサイトを見つけた。素晴らしい。
2011年5月 3日
Mac OS XへのBerkeley DBの最新版をインストールする
2011年5月 1日
Perlのクロージャ(closure)を学ぶ
Perlのクロージャ(closure)
Perlではクロージャが使えます。ではクロージャとは何か?
クロージャを概念から説明するのは非常に難しいです。でも使い方は非常に簡単です。なので、いきなりですがそのクロージャなるものを使ってみましょう。
File::Findモジュールを使ってファイルリストを作成する
File::Findモジュールは指定したディレクトリの階層を辿って全てのファイルをリストアップしてくれる便利な標準モジュールです。File::Findモジュールがエクスポートするfind関数にコールバック関数へのリファレンスを渡すと、指定したディレクトリの配下のファイル一つごとに、そのコールバック関数が呼ばれます。
例えば、ホームディレクトリのファイルを全て表示するスクリプトは以下の様になります。
package Search::File;
use File::Find;
sub lookup_file {
my $dir = shift;
find(\&process_file, $dir);
}
sub process_file {
print "$File::Find::name\n"; # File::Findモジュールが用意するファイルパスを保持する変数
}
package main;
Search::File::lookup_file($ENV{HOME});
対象のファイルは$File::Find::nameに設定されていますので、その内容を使って必要な処理を行います。
さて、File::Findモジュールのfind関数はコールバック関数へのリファレンスを受け取りますが、コールバック関数自体には引数も、返り値も有りません(帰り値は無視されます)。これではせっかく検索したファイルは何にも使えません(せいぜいprint関数で標準出力へ出力するぐらいです)。そこでlookup_file関数と、process_file関数の両方をスコープに持つレキシカル変数を用意してみましょう。
これでlookup_file関数と、process_file関数の間にインタフェースを持つことができます。
ちょっと動作は変わりましたが(全て一旦配列にファイルを保持するので、ファイル数が多いと表示されるまでに時間がかかります)、同じようにホームディレクトリ配下のファイルが全て表示されます。
package Search::File;
use File::Find;
my @file_list;
sub lookup_file {
my $dir = shift;
find(\&process_file, $dir);
foreach my $file (@file_list) {
print "$file\n";
}
}
sub process_file {
push @file_list, $File::Find::name;
}
package main;
Search::File::lookup_file($ENV{HOME});
これで得られたファイルのパスをコールバック関数の外へ渡す事ができるようになりました。これなら取得したファイルの一覧がコールバック関数の外で使えます。
しかし、これでは用意した変数@file_listはパッケージ全体(Search::File)をスコープとする変数になってしまいます。単にファイルのリストを受け渡すだけにしてはちょっとスコープが広すぎますね。適切な範囲に変数のスコープを狭めるのはプログラミングの基本中の基本です。
無名関数を使ってコールバック関数を書き換える
Perlには無名関数といって、コードの実行時に関数を定義する機能が有ります。この機能を使って、さきほどのコードを書き換えてみましょう。
package Search::File;
use File::Find;
sub lookup_file {
my $dir = shift;
my @file_list;
my $code = sub {
push @file_list, $File::Find::name;
};
find($code, $dir);
foreach my $file (@file_list) {
print "$file\n";
}
}
package main;
Search::File::lookup_file($ENV{HOME});
@file_listを定義している場所が変わりました。これで@file_listのスコープはlookup_file関数の中に閉じ込める事ができます。正しいスコープ設計は、すなわち正しいプログラミングです。
さて、新しく増えたのがmy $code = sub {...};という部分です。これは無名関数と呼ばれるPerlの機能で、実行時に関数を定義し、返り値としてコードへのリファレンスを得ます。
ポイントは、この定義した関数の中で@file_listを使っているところです。無名関数を定義した地点でスコープとして有効なレキシカル変数はそのまま使うことができるのです。
この動的に関数を定義した際に、スコープが有効な変数を"実行時に"使うことができる仕組みを「クロージャ」と言います。
改めて、「クロージャ」とは?
Perlにおけるクロージャは、コードブロックを定義した時に有効なレキシカル変数をコードブロックの実行時に使える仕組みです。つまり、スコープを関数などのコードブロックに閉じ込め、通常の変数スコープを超えても使える様にする仕組みなのです。
例えば、こんな簡単なコードも、クロージャを使っています。
{
my $count = 1;
sub count_up {
$count++;
}
}
print $count;
print count_up;
print count_up;
クロージャは、概念は難しいのですが利用するのは比較的簡単で、かつ強力な仕組みです。上記以外にも関数テンプレートや、オブジェクト機能の代替としての使い方など、非常に応用の利くテクニックなので、ぜひ覚えましょう。
2011/5/2:C言語の例を挙げていましたが、違うという指摘を頂きましたので削除しました。勘違いしていたようです。

