sub AS_ARRAY {
my $self=shift;
# do something useful here
}
####
$obj->[42]; # would be the same as
$obj->AS_ARRAY(42); # and so on...
####
@$m # entire matrix, your syntax: $m->()
$m->[ 1] # second row, your syntax $m->( 1);
$m->[ 1]->[ 0] # individual element, your syntax $m->( 1, 0);
####
package Matrix;
use strict; use warnings;
use Scalar::Util qw/refaddr/;
use Data::Dumper;
use base 'Exporter';
our @EXPORT='matrix';
use overload (
'""' => 'stringify',
'*' => 'mult',
'*=' => 'multby',
'**' => 'pow',
'&{}' => '_code',
);
sub matrix { Matrix->new(@_) }
sub mkaoa { [[ @_[0,1] ], [ @_[2,3] ]] }
{
my %entry;
my %code;
sub entry : lvalue {
my $id=refaddr shift;
@_==0 ? $entry{$id} :
@_==1 ? $entry{$id}[ $_[0] ] :
$entry{$id}[ $_[0] ][ $_[1] ];
}
sub _code : lvalue { $code{ refaddr shift} }
sub DESTROY {
my $id = refaddr shift;
delete $entry{ $id};
delete $code{ $id};
}
}
sub new {
my $class = shift;
my $self = bless( \ my $o, $class);
$self->init(@_);
}
sub init {
my $obj=shift;
$obj->_code = sub : lvalue {
$obj->entry(@_);
};
$obj->() = mkaoa @_;
$obj;
}
sub stringify {
my $m = shift;
"[[@{ $m->( 0) }] [@{ $m->( 1) }]]";
}
sub _mult {
my ($s,$o)=@_;
my $code = $s->_code;
$s->(0,0)*$o->(0,0) + $s->(0,1)*$o->(1,0),
$s->(0,0)*$o->(0,1) + $s->(0,1)*$o->(1,1),
$s->(1,0)*$o->(0,0) + $s->(1,1)*$o->(1,0),
$s->(1,0)*$o->(0,1) + $s->(1,1)*$o->(1,1);
}
sub mult {
my ($s,$o)=@_;
matrix $s->_mult($o)
}
sub multby {
my ($s,$o)=@_;
$s->() = mkaoa $s->_mult($o);
$s;
}
sub pow {
my ($self, $n) = @_;
my $out = matrix 1,0,0,1;
if ( $n < 6 ) {
$out->multby( $self) for 1 .. $n
} else {
my $pow = matrix map @$_, @{ $self->() }; # clone $self
while ( $n ) {
$out->multby( $pow) if $n & 1;
$pow->multby( $pow);
$n = int $n/2;
}
}
$out;
}
1;
__END__