Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

scalarmap - some new perl syntax

by ncw (Friar)
on Sep 01, 2000 at 02:02 UTC ( [id://30650]=perlcraft: print w/replies, xml ) Need Help??

   1: # This function works like map, except it produces a single scalar
   2: # output.  It hence maps an array into a scalar hence the (clumsy)
   3: # name scalarmap
   4: #
   5: # It requires 3 parameters
   6: # 1) A code block like map.  This will be passed $a and $b
   7: #    $a will be the result and $b is the current element
   8: #    it should return the new result
   9: # 2)  An initial value
  10: # 3) An array
  11: 
  12: sub scalarmap (&$@)
  13: {
  14:     my $code = shift;
  15:     local ($a, $b) = ( shift );
  16:     foreach $b (@_)
  17:     {
  18:         $a = &$code;
  19:     }
  20:     return $a;
  21: }
  22: 
  23: # Here are some examples
  24: 
  25: my @array = 1..10;
  26: 
  27: my $sum = scalarmap {  $a + $b } 0, @array;
  28: 
  29: my $sum_of_even_numbers = scalarmap {  $b & 1 ? $a : $a + $b } 0, @array;
  30: 
  31: my $factorial = scalarmap {  $a * $b } 1, @array;
  32: 
  33: my $fancy_join = scalarmap {  $a . $b } "", 'a'..'z';
  34: 
  35: # I don't suppose this will be actually useful in real life but it
  36: # amused me to make a twist an the all powerful map!
  37: #
  38: # This was inspired by a reference kudra made to subroutines and man
  39: # perlsub.

Replies are listed 'Best First'.
RE: scalarmap - some new perl syntax
by btrott (Parson) on Sep 01, 2000 at 02:26 UTC
    This is fun to play with. A few comments:
    • You wrote:
      my $fancy_join = scalarmap { $a . $b } "", 'a'..'z';
      This isn't doing what you think it is. If "" is the initial element, it's not going to be used to join each of the elements together into a string. Well, it's not going to do so as join would do it, at least. Try it with something like ", " to see.

      In case you don't feel like trying it, here's the results of:

      print scalarmap { $a . $b } ", ", 'a'..'z';
      , abcdefghijklmnopqrstuvwxyz
    • I'm not sure I like the use of $a and $b. That's too reminiscent of sort, where the elements are "equivalent" in terms of their relation to each other; they're both elements in the list, in other words.

      Here, though, $a is actually the *total* of whatever has come before in the list, where "total" means whatever you've defined it to mean in your code reference. And $b is just a lowly element. :)

      So they're not on the same "level" of meaning as it were. I like using $_ inside of map blocks. If it were me, I'd change $b to $_, and $a to something special and local, like $T, for total, or something like that. I don't know.

    • This is just getting snippy :), but I don't like having the initial value being the parameter following the code block. Because the code block is "acting" on the list, so it makes sense to follow the code block with the list.

      Maybe move the inital value in front of the code block?

    Anyway, I like this. Thanks for posting it.
      An advantage to $a and $b is that they [utomatically pass strict. (Specifically because of sort.)

      This is also a disadvantage, but oh well.

        That is why I chose $a and $b, because of the sort magic.

        I did consider setting $_ to a 2 element anonymous array, then you'd use it like this.

        scalarmap { $_->[0] + $_->[1] } 0, @z;
        But that isn't as elegant.

        I considered using $a and $_ but that offended me too!

        I see from merlyn's post below that the maker of List::Util::reduce came to the same conclusions...

      You are quite right about the join thing! I just wanted an example with a string and I didn't intend it to be a full blown join replacement!

      See my reply to tilly for $a and $b.

      I agree with you about having the initial value first, but I couldn't get it to work. Trying to prototype the subroutine as ($&@) meant that I couldn't call it for some reason.

      If I try this :-

      sub scalarmap ($&@) { local ($a, $b) = ( shift ); my $code = shift; foreach $b (@_) { $a = &$code; } return $a; } my @array = 1..10; my $sum = scalarmap 0, { $a + $b } @array;
      Then when I run it I get
      Array found where operator expected at scalarmap2.pl line 32, near " +} " (Missing operator before ?) syntax error at scalarmap2.pl line 32, near "} @array"
      Which is puzzling...
RE: scalarmap - some new perl syntax
by merlyn (Sage) on Sep 01, 2000 at 10:04 UTC
    What a great idea. In fact, it's so great, it's already been implemented (in C, with a fallback to Perl if the C fails to load) at List::Utils under the name reduce.

    And the reduce operator is one of the ideas to add into Perl6, so eventually we won't even need to get into a module. {grin}

    Something tells me that there isn't enough searching of the existing cool stuff in the CPAN going around. {grin}

    -- Randal L. Schwartz, Perl hacker

      I might have known that there would be a CPAN thingy to do it, and that merlyn would know of it {grin} ;-)

      Reduce is a much better name. It calls your sub with $a and $b set to the first two elements of the array which is neater in some ways, but would make it harder to write the factorial example above.

      Here is a related question - I tried to write the subroutine above with the paramters ($&@) but I couldn't then call the subroutine - looks like a bug... (I posted an example of this a bit further up the thread)

      BTW it is List::Util

        You wrote:
        > It calls your sub with $a and $b set to the first two > elements of the array which is neater in some ways, > but would make it harder to write the factorial example > above.
        How so? Your initial value is, in this case, really just the first element of the array, in the case of reduce (I didn't realize this until looking at reduce, granted). So you'd just make your array 1..$N for a factorial. Like this:
        sub factorial { reduce { $a * $b } 1..$_[0] }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (4)
As of 2024-03-28 16:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found