
これまでのあらすじから。
- Perl で JS の arguments.callee 的なことしようと思ってハマった - IT戦記
- それDevel::Caller でできるよ - TokuLog 改め だまってコードを書けよハゲ
- 404 Blog Not Found:perl - で(Recall()|arguments.callee()|&?BLOCK())
- PerlでRecallの話 - Unknown::Programming
これ、それぞれに欠点がありました。Devel::CallerはXSに依存する。弾方式はソースフィルター、id:fbis方式はいちいち自分自身をスタックに積み直している...
この欠点を全て取り除く方法を発見しました。
[Run via codepad]#!/usr/local/bin/perl use strict; use warnings; our $CALLEE = 'whatever'; # just a place holder sub recsub(&) { my $code = shift; sub { local *CALLEE = \$code; $code->(@_); } } my $fact = recsub { $_[0] <= 1 ? 1 : $_[0] * $CALLEE->($_[0]-1) }; my $fib = recsub { $_[0] <= 1 ? 1 : $CALLEE->($_[0]-2) + $CALLEE->($_[0]-1)}; warn $fact->($_) for ( 1 .. 10 ); warn $fib->($_) for ( 1 .. 10 ); warn $CALLEE;
XSに依存しません。ソースフィルターにかけません。スタックに余計な物は積みません。
で、よろこびいさんで CPANize しようと思ったら....先達がいました。
全く同じ発想です。$CALLEE
でなくて$REC
ではありますが。
ちなみに、myではなくourを使っている理由は、モジュール化した際にexportすることを考えていたから。それがなければ
[Run via codepad]my $CALLEE; # just a place holder sub recsub(&) { my $code = shift; sub { $CALLEE = $code; my $ret = $code->(@_); $CALLEE = undef; $ret; } }
でも行けます。
Dan the Wheel Reinventing Perl Monger
その方が時間単価の低いアプリケーションプログラマーには丁度良い。