Higher Order Perlのappend()
- listをイテレータにする関数を作る
- イテレータをいくつかリストに突っ込む
- さっきのlistをイテレータにする関数を使ってイテレータの詰まったリストをイテレータに
イテレータのappendの完成。素晴らしい。この流れでイテレータのzipとかもやれそう。
Mark Jason Dominus
Morgan Kaufmann Pub / ¥ 7,625 (2005-05-30)
通常24時間以内に発送
Higher Order Perlのappend()
イテレータのappendの完成。素晴らしい。この流れでイテレータのzipとかもやれそう。
最後の式を評価して返す
func {なんかコード} = func(sub {なんかコード})の略らしい
sub Testfunc (&){return $_[0]->();}
Testfunc {print "hello kzfm"};
これはうまく動くが(&)がないと
sub Testfunc {return $_[0]->();}
Testfunc {print "hello kzfm"};
下のようなエラーが出る。
Not a CODE reference at test.pl line 1.
デバッガ動かしてみると先にTestfunc {print "hello kzfm"}がブロックとして評価されて、その後Testfunc {return $_[0]->();}が評価されるので$_[0]がコードブロックじゃないといわれているようだ。
プロトタイプで(&)ってことはコードブロック受け取ってるってことだよな。無名関数ってコードブロックか、、、あーなんとなくわかってきた気が。やっと{}がlispの括弧に見えてきた。
HOP3章終了。
"0e0"の使いどころがなかなか。
論理演算
$ "0e0" || 1
0e0
$ 0 || 1
1
真と判定、で演算してみる。
$ "0e0" * 5
0
$ "0e0" + 5
5
$ "0e0" - 5
-5
数値だ
$ "0e0" == 0
1
$ "0e0" eq 0
論理演算で真を返すのに0
で、これがどう便利かというと
$cached{$key} ||= make_cache($key)
キャッシュに0が入ってる場合偽と判定されてしまい、キャッシュがあるのに再計算してしまうのだけど"0e0"を入れておくときちんとキャッシュが効くと。
HOPではOrcish maneuverに絡めてあって、3章はこの部分が一番面白かった。4章はイテレータ、この章に100p近く割いてある。
splitにはlimitパラメータがあることをHOP読んでて知った。
$ $t = "a b c d e"
$ split /\ +/, $t
a
b
c
d
e
$ split /\ +/, $t , 2
a
b c d e
splitっていろいろできんじゃん。
5章まで読んだけど、(たいして理解してなかったので)もう一度最初から読んでみる。
prefaceにこの本はSICPにインスパイアされて書いたでよって書いてあった。
Gaucheのdisplayとprintってperlのprintとsayと似たような関係なんだろうか?と思った。
参考にしたサイト
継続渡しスタイルに載ってたcall-with-procedureをperlで。
sub call_with_procedure {
my ($exp,$proc) = @_;
$proc->($exp);
}
sub fact {
my $n = shift;
$n == 1 ? 1 : $n * fact($n-1);
}
print call_with_procedure(sub {2 * $_[0]}, sub {$_[0]->(fact(10))});
実行すると
$ perl curpr.pl
7257600
継続ってのはgaucheだと外に向いているようなものを内側にひっくり返す感があってなんか奇妙な感じがするが、いくつか書いてみてから継続の説明を読むと、なんかフムフム感が得られる。だけど、それをperlでやろうとするとひどく混乱するのはなぜだろうか?
sub {$_[0]->(fact(10))}->(sub {2 * $_[0]})
= {2 * $_[0]}->(fact(10))
= 2 * fact(10)
書き下してみるとこんな感じか、、、、
最初のsub{}->()ってコードはautoboxを使えば動きそうな気がするが、、、
実際にやってみることにした。
use autobox;
use autobox::Core;
sub fact {
my $n = shift;
$n == 1 ? 1 : $n * fact($n-1);
}
print sub {$_[0]->(fact(10))}->(sub {2 * $_[0]});
無名サブルーチンが第一引数に無名サブルーチンを取ってこれが引数にfact10の結果を取ってそれを二倍するっていう処理が実行される(はず)
$ perl abtest.pl
7257600
動いた!
call/ccの勉強してたのに、キモコードを動かすというあらぬ方向に行ってしまったが、ファーストクラスオブジェクトってのがなんだかわかったようなわからんようなホンワカした何かを得た感があったのでよしとしよう。
継続ブーム到来中。なんでも継続読みましたよ、何度も何度も読みまくりなのでなんども継続
もちろんperlでもやってみたくなるので、なんでも継続、Perl で。とか継続は力なり読みながら手を動かしてみた。
が、perlだと、クロージャの中の
my $dummy = $cont; # なぜか必要みたい。
ってのが何故必要なのかわからないし、なんでそんなへんなのがそこにあるのかが、凄い気になるのでデバッガで追いかけた。
該当行を
#my $dummy = $cont; # なぜか必要みたい。
として perl -dで起動してみるといつまでたっても終わらない。なんか無限ループしてるっぽい。mとnの値がどんどんでかくなっていってるみたいだし、、、、。デバッガじゃなくて何が渡されてるのかprintしてみる。
sub {
my ($n) = @_;
my $dummy = $cont; # なぜか必要みたい。
print "n: $n\n";
&leaf_count_cps ($tree->[1],
sub {
my ($m) = @_;
print "m: $m\n";
$cont->($n + $m);
});
});
とやってnとmを追いかけると、おまじない入りは
$ perl cont.pl # [["a", "b"], [["c", "d"], "e"]];
n: 1
m: 1
n: 2
n: 1
m: 1
n: 2
m: 1
m: 3
5
予想通りの挙動。
で、my $dummy = $contが評価されないようにしてみると
$ perl cont.pl# [["a", "b"], [["c", "d"], "e"]];
n: 1
m: 1
n: 2
m: 1
m: 3
n: 4
m: 1
m: 5
m: 7
...ずっと続く...
よくわからん。別に代入じゃなくて$contをprintしてもrefしても正常に実行されるので、クロージャの中に評価する式があることが重要みたいなんだけど、、、
4:実体をそのまま覚えるためには、サブルーチン内でもそのレキシカル変数が使われていなくてはならない。 (サブルーチン内にその変数がなければ、実質サブルーチンはその変数を知らないのと同じコトになる)
これとか関係あるのだろうか?
goto使った継続だとおまじないがいらないってのもまた謎なんだよなぁ。
28082007 perl
単純なピボットがしたかった。
use Text::CSV::Simple;
my $file = shift;
my $parser = Text::CSV::Simple->new;
my @list = qw/cl1 cl2 cl3 cl4 cl5/;
$parser->field_map(@list);
my @data = $parser->read_file($file);
my $pivdata = {};
for my $d (@data){
for my $label (@list){
push @{$pivdata->{$label}},$d->{$label};
}
}
for my $label (@list){
print join ",", @{$pivdata->{$label}};
print "\n";
}