Em Dom, 2009-06-07 às 00:07 +0200, Daniel Carrera escreveu:
> Daniel Ruoso wrote:
> >> Are you planning to write a post explaining how your program works?
> > Maybe, but if you want to beat me to it, feel free ;)
> >> I figure that the explanation is as useful as the example. I sure
> >> spent a lot of time writing the blog post.
> > I'm not sure I'll have the time to write it soon, but it will certainly
> > be on my list, unless you kindly post about it first ;)
> Honestly, I don't really know how your version works.

I'll take the code as in http://sial.org/pbot/37089
Feel free to post it if you like...

Ok, I think I can skip the first part, where I declare a token Num,
since your example explain it in great detail.

At first I'm using multi subs, the declaration is just

 multi name ($a, $b) {...}

and is just a shortcut for

 our multi sub name ($a, $b) {...}

which means we're declaring a sub named '&name' which will also be
registered in the current package (our), with the signature inside the
parens. This will work mostly as multis work in other languages, it will
invoke the variant which signature matches the parameters.

The second point is the use of the "infix:<rpn>" name in the multi. This
is how you declare new operators in Perl 6. infix describe the syntatic
category of the operator, in this specific case, it means the operator
stays between two values. So, after defining the multi sub, I could just
use:

 5 rpn 4

and this would invoke

 infix:<rpn>(5, 4)

If you're following until here, you probably realize that I could also
do

 ((5 rpn 4) rpn '+') rpn 3

but Perl 6 has the "reduce meta operator", which takes any infix
operator and builds the above grouping for an arbitrary list, and that's
the last line of the code

  [rpn] @*ARGS[0].words;

This takes the list of words in @*ARGS[0] (which means I require a space
between every token) and reduces it using the infix:<rpn> operator,
which is implemented by each of the variants in the code.

The reduce meta-op works by taking the first two elements of the list
and running the infix:<rpn> with them as parameters, take the result of
that and the next element of the list and call it again, then do it
again until the list ends.

The last thing you need to know to understand this is about subsets, as
used in the signature of most variants

 multi infix:<rpn> ($a where /<Num>/, $b where /<Num>/) {...}

This signature will take two arguments where both must match the Num
token. This happens to be the variant that matches the start of the
list, and it is the only one that doesn't expect an Array as the first
argument, because it will itself return an Array with the two numbers.
As the reduce metaop takes the result from this call and the next
element on the list to call the sub again, the next call will receive an
array with the two first numbers as the first argument and the next
token as second argument, then the signature match does its trick and we
go on until we reach the end of the list, and the last calculation is
made.

This solution is mostly a functional solution. Probably if you ask the
LISP guys to work on a program to do RPN, it will probably look like
this...

daniel

Reply via email to