Often in my coding labors I wish for alternative forms of certain infix operators, such as + or &&, that I could use with an arbitrary number of operands. This is no mere boast of monkly laziness! It's not just a matter of not wanting to write all those +s and &&s. There are times when the number of operands is not known until runtime... Well, come to think of it, it is still a case of monkly laziness.

A very risky kluge I have encountered in my readings of Perl code is this sort of thing:

$sum = eval join ' + ', @addends;
or
$all_true = eval join ' && ', @flags;
Yikes. If @flags contains an undef the last expression "works" only because the eval fails with a syntax error. The counterpart using ' || ' can't even pretend to work.

A better alternative is to go ahead and define

sub AND { ! grep !$_, @_ } sub OR { !!grep $_, @_ }
Simple, nice and symmetrical, and they do the right thing even for an empty @_:
DB<1> p AND() 1 DB<2> p AND(0) DB<3> p AND(1) 1 DB<4> p AND(2, 3, 0, 1) DB<5> p OR() DB<6> p OR(1) 1 DB<7> p OR(2, 3, 0, 1) 1
The fly in this ointment is that, unlike && and ||, AND and OR as defined above are not short-circuiting: every member of @_ is checked by grep, whether the answer requires it or not. It would be nice to have something like grep that returned only the first element of a list that passed a test.

As it happens, there is such a thing in List::Util. From the docs:

first BLOCK LIST
Similar to "grep" in that it evaluates BLOCK setting $_ to each element of LIST in turn. "first" returns the first element where the result from BLOCK is a true value. If BLOCK never returns true or LIST was empty then "undef" is returned.
OK, so we try
use List::Util 'first'; sub AND { ! first { !$_ } @_ } sub OR { !!first { $_ } @_ }
This OR works fine:
DB<1> p OR(0) DB<2> p OR() DB<3> p OR(1) 1 DB<4> p OR(undef, 2, 0, 'x') 1
The AND, not so good:
DB<1> p AND(0) 1 DB<2> p AND() 1 DB<3> p AND(1) 1 DB<4> p AND(undef, 2, 0, 'x') 1
The problem is that in this implementation of AND, the outer ! is no longer negating the answer to the question "how many falses did you find", but rather it's negating that first false found. But it's worse than that: first is inherently ambiguous with tests like { ! $_ } or { ! defined $_ }, because a return value of undef could either mean "I didn't find any" or "I found this one." Maybe first is not the way to go.

OK, let's try something slightly more verbose but more straightforward:

sub AND { $_ || return 0 for @_; 1 } sub OR { $_ && return 1 for @_; 0 } __END__ DB<1> p AND(0) 0 DB<2> p AND() 1 DB<3> p AND(1) 1 DB<4> p AND(undef, 2, 0, 'x') 0 DB<5> p OR(0) 0 DB<6> p OR() 0 DB<7> p OR(1) 1 DB<8> p OR(undef, 2, 0, 'x') 1
It is good. The gods of Perl have found pleasure in putting a little bit of || in AND, and a little bit of && in OR. A case of Perl ying-yang.

But even though List::Util::first did not help with AND and OR, the very handy function List::Util::reduce can be used to generate multi-argument counterparts of other infix operators:

use List::Util 'reduce'; sub add { reduce { $a + $b } ( 0, @_ ) } sub mult { reduce { $a * $b } ( 1, @_ ) }
(The added 0 and 1 make sure that these behave righteously when @_ is empty.) List::Util::reduce is a truly handy little function, one that I wish had made to the Perl core; the docs have more examples of its usefulness.

And while I'm praying to the gods of Perl for new admissions to the core, let me pray for multiarg counterparts for all those infix operators for which they would make sense.

the lowliest monk

In reply to An infix fix by tlm

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.