これを見てふと思い立って作りました。

404 Blog Not Found:たらいを回すならHaskell-goroさんのコメント
Perlなら標準ライブラリにMemoize搭載でっせ。
use Memoize;
memoize('tak');

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::MemoizeAttribute::Utilを上げた際に消してしまったからの模様。現在対策協議中。