これを見てふと思い立って作りました。
404 Blog Not Found:たらいを回すならHaskell-goroさんのコメントPerlなら標準ライブラリにMemoize搭載でっせ。use Memoize; memoize('tak');
- Get via CPAN (Available Now!)
- Get via www.dan.co.jp
Memoizeの作者のMJDとは、台北で一緒に温泉に入った仲。私がMemoizeのことを知らないわけがありません:p
ですが、こうした方がInterfaceとしてはいいのではないかなあと思ってつくったわけです。
use strict; use warnings; use Attribute::Memoize; no warnings 'recursion'; sub tak : Memoize { my ($x, $y, $z) = @_; ($x <= $y) ? $y : tak(tak($x-1, $y, $z), tak($y-1, $z, $x), tak($z-1, $x, $y)); } my ($x, $y, $z) = @ARGV ? @ARGV : (10, 5, 0); print "tak($x, $y, $z) = ", tak($x, $y, $z), "\n"; __END__
実装は、嘘のように簡単です。
package Attribute::Memoize; use 5.008001; use strict; use warnings; our $VERSION = sprintf "%d.%02d", q$Revision: 0.1 $ =~ /(\d+)/g; use Attribute::Handlers; use Memoize; sub UNIVERSAL::Memoize :ATTR(CODE) { my ($package, $symbol, $referent, $attr, $data, $phase) = @_; my $funcname = $package . '::' . *{$symbol}{NAME}; memoize $funcname, @$data; } 1;
Enjoy!
Dan the Memoized Man
NAME Attribute::Memoize - Memoize your sub via attribute SYNOPSIS use Attribute::Memoize; sub fib : Memoize { return $_[0] < 2 ? $_[0] : fib($_[0]-1) + fib($_[0]-2); } DESCRIPTION Attribute::Memoize memoizes your sub via attribute. The code above is exactly identical to: use Memoize; memoize('fib') sub fib : Memoize { return $_[0] < 2 ? $_[0] : fib($_[0]-1) + fib($_[0]-2); } But more DWIMery. CAVEAT You can also pass memoize options as follows; use Attribute::Memoize; sub fib : Memoize(LIST_CACHE => MERGE) { return $_[0] < 2 ? $_[0] : fib($_[0]-1) + fib($_[0]-2); } But you have to be careful if you want to do something like: my %cache; sub fib : Memoize(SCALAR_CACHE => [HASH => \%cache]) { return $_[0] < 2 ? $_[0] : fib($_[0]-1) + fib($_[0]-2); } print fib(42), "\n"; use Data::Dumper; print Dumper \%cache; You'd be surprised to find that %cache is empty. This is because the attribute handling is done in CHECK phase so %cache points to nowhere. You can overcome this as follows; our %cache; # so it is visible sub fib : Memoize(SCALAR_CACHE => [HASH => \%cache]) { return $_[0] < 2 ? $_[0] : fib($_[0]-1) + fib($_[0]-2); } print fib(42), "\n"; use Data::Dumper; print Dumper \%cache; Well, if you want this kind of minute control, IMHO simply using Memoize should do better. EXPORT None by default. SEE ALSO Attribute::Handler, Memoize AUTHOR Dan Kogai, <dankogai@dan.co.jp> COPYRIGHT AND LICENSE Copyright (C) 2006 by Dan Kogai This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available.
追伸: 何とあのautoboxのchocholateboyご本人から、車輪の再発明との連絡を受けました。Attribute::Utilに:Memoizeの実装が含まれています(しかも手法もほとんど同じ)。一応CPANをきちんと検索したのにこうなったのは、作者のmarcelがかつてUploadしていたAttribute::MemoizeをAttribute::Utilを上げた際に消してしまったからの模様。現在対策協議中。
そっか、「魔法」は便利ですが、それだけ知っても応用が効きませんもんね。