逆ポーランド計算機 Perl版

Perlで書いたらだいぶ簡単ですね。
やっぱりサブルーチンリファレンスがあると
気持ち楽にかけます。

#!/usr/local/bin/perl

package ReversePolish;

use Moose;
use MooseX::AttributeHelpers;

has stack => (
    metaclass  => 'Collection::Array',
    is         => 'rw',
    isa        => 'ArrayRef[Int]',
    default    => sub { +[]; },
    provides   => {
        push => 'push_number',
        pop  => 'pop_number',
    },
);

__PACKAGE__->meta->make_immutable;

use Scalar::Util qw(looks_like_number);

my %operator = (
    '+' => sub {
        my ($a, $b) = @_;
        return $a + $b;
    },

    '-' => sub {
        my ($a, $b) = @_;
        return $a - $b;
    },

    '*' => sub {
        my ($a, $b) = @_;
        return $a * $b;
    },

    '/' => sub {
        my ($a, $b) = @_;
        die "Error : Zero divided\n" if $b == 0;
        return $a / $b;
    },

    '%' => sub {
        my ($a, $b) = @_;
        die "Error : Zero divided\n" if $b == 0;
        return $a % $b;
    },
);

sub calc {
    my ($self, $input) = @_;

    my @inputs = split /[\s\t]/, $input;

    foreach my $term (@inputs) {
        if ( looks_like_number($term) ) {
            $self->push_number($term);
        } elsif ( exists $operator{$term} ) {
            my $op2 = $self->pop_number();
            my $op1 = $self->pop_number();

            my $val = $operator{$term}->($op1, $op2);

            $self->push_number($val);
        } else {
            Carp::croak("Invalid input\n");
        }
    }

    my $ret_val = $self->pop_number();

    Carp::croak("Error : data is left in stack\n") if scalar @{$self->stack};

    return $ret_val;
}

package main;

use Test::More;

my $reverse_calcurator = ReversePolish->new();

is($reverse_calcurator->calc("1 2 +"), 3);
is($reverse_calcurator->calc("3 2 -"), 1);
is($reverse_calcurator->calc("9 2 *"), 18);
is($reverse_calcurator->calc("91 7 /"), 13);
is($reverse_calcurator->calc("91 5 %"), 1);

done_testing();