in reply to An infix fix

If you wanted to use List::Util::first for AND and OR, these work:
sub AND { my $last; first {!($last = $_)} @_ or $last; } sub OR { my $last; first {($last = $_)} @_ and $last; }
Again, the little bit of yin-yang.

I note that the short-circuiting you mention isn't quite as good as the short-circuiting you get with the actual operators, since each element of the list will be evaluated prior to calling the function. So you don't have to traverse the entire list, but any function calls and assignments within the list will be executed.

I note also that you're just exchanging the && operator for a comma (plus the function calling semantics). I had thought that overloading the comma operator would be a clever alternative, but it turns out not to be overloadable.

Our functional-programming brethren might prefer the tail-recursive

sub OR { @_ > 1 ? shift || OR(@_) : shift; } sub AND { @_ > 1 ? shift && AND(@_) : shift; }
Update: tail-recursive ones were buggy.

Caution: Contents may have been coded under pressure.

Replies are listed 'Best First'.
Re^2: An infix fix
by tlm (Prior) on Mar 22, 2005 at 21:56 UTC
    Our functional-programming brethren might prefer the tail-recursive
    sub OR { @_ > 1 ? shift || OR(@_) : shift; } sub AND { @_ > 1 ? shift && AND(@_) : shift; }
    <pedantic> AND() should be true.
    sub OR { @_ ? shift || OR(@_) : 0; } sub AND { @_ ? shift && AND(@_) : 1; }
    </pedantic>

    the lowliest monk

      I really like the simplicity and symmetry, but I was (and still am) a little hung up on making them behave as their 2-argument operators do. So I certainly can't hold your pedantry against you. :-)

      If you call them ANY and ALL, I go with your definitions. As AND and OR, I think they should behave as the ops: AND returns the first false value, or the last true value if no false values are encountered; OR returns the first true value, or the last false value if no true values are encountered. That definition extends easily to one argument, but leaves the zero-argument case undefined.


      Caution: Contents may have been coded under pressure.
        As AND and OR, I think they should behave as the ops: AND returns the first false value, or the last true value if no false values are encountered; OR returns the first true value, or the last false value if no true values are encountered.
        I'd be curious to learn how the languages that have multi-arg AND and OR resolve this question. Of the languages I'm familiar with only Scheme fits this description, and, at least in the Scheme implementations I have on my machine (PLT Scheme/mzscheme and MIT Scheme), (and) is true and (or) is false; e.g. (for MIT Scheme):
        1 ]=> (and) ;Value: #t 1 ]=> (and 3) ;Value: 3 1 ]=> (and 0) ;Value: 0 1 ]=> (or) ;Value: () 1 ]=> (or 3) ;Value: 3 1 ]=> (or 0) ;Value: 0
        The way I understand these generalized versions of these functions is that AND is false if any of its arguments is false, true otherwise; OR is true if any of its arguments is true, false otherwise. In this formulation, the case of no arguments is not problematic.

        the lowliest monk

      Come to think of it, none of these recursive subs are tail recursive. They all have a pending && or || business when they return.

      I can't think of a simple way to make them tail recursive. The best I can come up with requires using "helper functions":

      sub OR { _OR (0, @_) } sub AND { _AND(1, @_) } sub _OR { my $s = shift; @_ && !$s ? _OR ( $s || shift, @_ ) : $s } sub _AND { my $s = shift; @_ && $s ? _AND( $s && shift, @_ ) : $s }

      the lowliest monk

        The operator is finished when it calls the right hand side -- the value of the RHS is the value of the expression, at that point. All that's left is to return up the stack. It's the flip-side of short-circuiting.

        Caution: Contents may have been coded under pressure.