fREW++ and pmichaud++ have, between them, three versions of the RPN calculator. Here is a fourth, clener in some ways.
You can use it as follows:
> ./perl6 rpn.pl '4 5 9 sqrt + *' 32 > ./perl6 rpn.pl '4 5 9 sqrt rotate3 + *' 35
my %op_dispatch_table = { '+' => { $^a + $^b }, '-' => { $^a - $^b }, '*' => { $^a * $^b }, '/' => { $^a / $^b }, 'sqrt' => { $^a.sqrt }, 'say' => { $^a.say; $^a}, 'rotate3' => { ($^b, $^c, $^a) }, }; sub evaluate (%odt, $expr) { my @stack; my @tokens = $expr.split(/\s+/); for @tokens { when /^\d+$/ { @stack.push($_); } when ?%odt{$_} { my $f = %odt{$_}; my @top_terms = gather { for 1..$f.arity { take @stack.pop} }; @top_terms = reverse(@top_terms); my @to_push = $f.(|@top_terms); @stack.push(@to_push); } default { die "Unrecognized token '$_'; aborting"; } } @stack.pop; }
say "Result: { evaluate(%op_dispatch_table, @*ARGS[0]) }";
I have to say that I've seen the other examples of this and I think this is definitely the cleanest and easiest to understand. Using $^a, $^b and $^c with the arity checks definitely beats all those pops, shifts, etc.
I agree, though I think it might need a special-case for zero-arity so that could could write an arbitrary reduction:
'sum' => { @stack = [+] @stack },
hmm, can that be written as assignment-operator?
'sum' => { @stack [+]= () },
Re:but just one thing more
amahabal on 2009-03-04T04:12:48
I was hoping to use zero arity like so:'pi' => { 3.1415926 }
Perhaps
'sum' => { @stack = [+]@stack; } but WholeStack,
or something along those lines would work.