[[PageOutline(2, 目次, inline)]]
Higher-Order Perl という本で有名な人。通称 mjd. 日本の Perl ギークは「マジデ」と呼ぶ。(こともある。)
プレゼンの内容は Higher-Order Perl にも書かれてるみたい。
高階関数やクロージャを使うと、構文解析プログラムがこんなにすっきり書けるよ!というお話。
このプレゼン自体では、高階関数やクロージャの説明がなかった。ので簡単に説明すると、クロージャとは、Perl で書くとこんな感じ。(言葉の定義は Wikipedia とか参照。たぶん、言葉の定義だけ見てもよくわからないと思う。)
#!perl
#!/usr/bin/perl
use strict;
use wanings;
sub calc {
my $op = shift;
return sub {
my ( $a, $b ) = @_;
return eval "$a $op $b";
};
# このリターンされている無名サブルーチンがクロージャ。
# サブルーチンの外で定義されている $op を内部で参照している
# ことに注目。この様に外部で定義された変数を内部に閉じ込める
# ので「クロージャ(Closure, 閉包)」と呼ばれる。
}
my $plus = calc('+');
print $plus->(3, 2); # 結果は 5
my $minus = calc('-');
print $minus->(3, 2); # 結果は 1
こんな感じで、加算する関数と減算する関数を、ひとつの関数定義から生成できる、という感じで、クロージャを使うと似たような関数の生成が楽になる。(クロージャの用法はこれ以外にもあるけど。)
また高階関数とは、「関数を引数にとる関数」のこと。例えばこんな感じ。
#!perl
#!/usr/bin/perl
use strict;
use warnings;
sub calc {
my $op = shift;
return sub {
my ( $a, $b ) = @_;
return eval "$a $op $b";
};
}
my $plus = calc('+');
my $minus = calc('-');
# ここまではクロージャの例と一緒
# 複数の関数の結果を掛け合わせる関数
# これが高階関数
# 引数だけでなく、結果も関数となっている(クロージャ)
sub multiply {
my @funcs = @_;
return sub {
my ( $a, $b ) = @_;
my $result = 1;
for ( @funcs ) {
$result *= $_->($a, $b);
}
return $result;
};
}
# 加算関数と減算関数を掛け合わせる関数を multiply で生成し、
# 引数に 5 と 3 を与える
multiply($plus, $minus)->(5, 3); # ( 5 + 3 ) * ( 5 - 3 ) が実行され結果は 16
高階関数とかクロージャとか知らない人は、これだけでお腹いっぱいになる気がする。
クロージャとか高階関数って、どんなものかは知っていても、使うことがあまりなかったり、どう使うのかがよく分からなかったりするが、このプレゼンでの構文解析プログラムがその回答のひとつ。
あとは細かい Perl コードの話になるので省略。クロージャ使って似たようなパーサコードの生成を簡略化し、連続した関数の実行を if + && でやっているところを、高階関数をつかうことによってまとめてすっきりさせる、というのがだいたいの流れ。
あと、「バックトラッキングも重要だけど、詳しくは本を読んで」とのこと。
Ingy からの「Wiki パーサにも応用できるか」との質問に「できる」と回答してた。自分も Trac の Wiki 記法パーサモジュールを CPAN にあげてるので、参考になりそう。特に、リストのパースは自分で書いた処理がいけてなくて、時々動きがおかしかったりするのだけど、これを参考にすれば いい感じで書けそうだ。というわけで、Higher-Order Perl 買う。
Perl の「今風な」ネットワークプログラミングに関するお話。
...
イベントベースで並列化
システムコールの抽象化
プログラミングを容易にしてくれるコンポーネントがたくさん
POE::Loop::Epoll
memcached のビルトインサポート
#!perl Data::ObjectDriver::Driver::Cache::Memcached->new( cache => Cache::Memcached->new({ servers => [ ... ] }), fallback => Data::ObjectDriver::Driver::DBI->new( dsn => 'dbi:SQLite:dbname=global.db', ), );
#!perl
Data::ObjectDriver::Driver::Cache::Cache->new(
cache => Cache::Memcached->new({ servers => [ ... ] }),
fallback => Data::ObjectDriver::Driver::SimplePartiotion->new(
using => 'Recipe',
),
);
Livedoor でも LiveDoor でもなく livedoor が正しい
WEB+DB PRESS とかまるごと Perl とか見れば詳しく載ってる。