In a Reverse Polish Notation Calculator, fREW Schmidt takes the RPN calculator example from Higher Order Perl and converts it over to Perl 6.
Very cool.
But as usual, I visually look at the Perl 6 version compared to the Perl 5 version and think "Can't we do better?" In this case, we can. Here's my version of the same code:
my %op_dispatch_table = {
'+' => { .push(.pop + .pop) },
'-' => { my $s = .pop; .push(.pop - $s) },
'*' => { .push(.pop * .pop) },
'/' => { my $s = .pop; .push(.pop / $s) },
'sqrt' => { .push(.pop.sqrt) },
};
sub evaluate (%odt, $expr) {
my @stack;
my @tokens = $expr.split(/\s+/);
for @tokens {
when /\d+/ { @stack.push($_); }
when ?%odt{$_} { %odt{$_}(@stack); }
default { die "Unrecognized token '$_'; aborting"; }
}
@stack.pop;
}
say "Result: { evaluate(%op_dispatch_table, @*ARGS[0]) }";
$ ./perl6 calc.pl '5 6 +' Result: 11
my %op_dispatch_table = {
'+' => { .push(.pop + .pop) },
'-' => { .push(.pop R- .pop) },
'*' => { .push(.pop * .pop) },
'/' => { .push(.pop R/ .pop) },
'sqrt' => { .push(.pop.sqrt) },
};
sub evaluate (%odt, $expr) {
my @stack;
my @tokens = $expr.split(/\s+/);
for @tokens {
when /\d+/ { @stack.push($_); }
when ?%odt{$_} { %odt{$_}(@stack); }
default { die "Unrecognized token '$_'; aborting"; }
}
@stack.pop;
}
say "Result: { evaluate(%op_dispatch_table, @*ARGS[0]) }";
Re:Making it even more compact...
pmichaud on 2009-03-03T15:09:21
Yes, it could potentially be made slightly shorter... but I like the straightforward clarity of the above. An advantage of the above approach is that it would work for almost any stack pattern -- including things that don't fit the ".push( fn(.pop) )" model. For example, to add a 'say' operator that displays the top value of the stack (without removing it):
'say' => {
.[*-1].say } I can also imagine functions that rotate or swap the top N operands, or the like. Trying to wedge those into a standard
.push/.pop sequence seems a little less straightforward than what we have above. I'd still be interested in seeing the solution you have in mind, even if Rakudo doesn't compile/run it yet. In fact, we'd be a bit more likely to make it do that if we had an example to work to.
:-) Thanks!
Pm
Re:Making it even more compact...
amahabal on 2009-03-03T18:58:57
I have one version here:
http://use.perl.org/user/amahabal/journal/38583
Thanks to your suggestion, I added 'say' and 'rotate3'. I will try my original idea next, for which I need to go from a name (such as 'double') to a callable object (&double). Not sure yet what I'd do with multis and such, but I will see how far I get.