I would take a functional-programming approach. First, I would put the desired mathematical operators in a hash that maps each operator's command-line form to the function that performs the operation:
sub printN($) { my $format = shift; sub { sprintf $format, @_ } } my %functions = ( -power => sub { exp( $_[0] )}, -log2 => sub { log( $_[0] )/log(2.0) }, -loge => sub { log( $_[0] ) }, -log10 => sub { log( $_[0] )/log(10.0) }, -round => sub { int($_[0] + ($_[0] <=> 0)*0.5) }, -trunc => sub { int $_[0] }, -f1 => printN "%.1f", -f2 => printN "%.2f", -f3 => printN "%.3f", -f4 => printN "%.4f", -f5 => printN "%.5f", );
(I used a helper function to build the printf functions for me.)

Second, I would parse the command line to extract, in order, the operators to be performed:

my @func_pipeline = grep {$_} map {$functions{"$_"}} @ARGV; @ARGV = grep {!$functions{"$_"}} @ARGV;

At this point, @func_pipeline contains the functions corresponding to the operators we want to apply. I would then use function composition to glue the functions together, to result in a single function that performs the entire pipeline:

sub compose($$) { my ($f, $g) = @_; sub { $f->( $g->(@_) ) } } sub id { @_ }; # identity function my $composite_fn = reduce {compose($a,$b)} @func_pipeline, \&id;
(The above uses the ever-handy reduce from List::Util.)

Finally, I would apply the composite function to each word of input, line by line:

print join ' ', map $composite_fn->($_), split while <>;
That's it. Putting it all together into a program, gives this:
#!/usr/bin/perl -l use strict; use List::Util qw( reduce ); sub printN($) { my $format = shift; sub { sprintf $format, @_ } } sub compose($$) { my ($f, $g) = @_; sub { $f->( $g->(@_) ) } } sub id { @_ }; # identity function my %functions = ( -power => sub { exp( $_[0] )}, -log2 => sub { log( $_[0] )/log(2.0) }, -loge => sub { log( $_[0] ) }, -log10 => sub { log( $_[0] )/log(10.0) }, -round => sub { int($_[0] + ($_[0] <=> 0)*0.5) }, -trunc => sub { int $_[0] }, -f1 => printN "%.1f", -f2 => printN "%.2f", -f3 => printN "%.3f", -f4 => printN "%.4f", -f5 => printN "%.5f", ); my @func_pipeline = grep {$_} map {$functions{"$_"}} @ARGV; @ARGV = grep {!$functions{"$_"}} @ARGV; my $composite_fn = reduce {compose($a,$b)} @func_pipeline, \&id; print join ' ', map $composite_fn->($_), split while <>;
As an example, let's print (with 4-digit precision) the result of "powering" the numbers 1 2 3:
$ echo 1 2 3 | ./calc-pipeline -f4 -power 2.7183 7.3891 20.0855
There you have it!

Cheers,
Tom


In reply to Re: Dynamic function chains? by tmoertel
in thread Dynamic function chains? by keymon

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.