in reply to Re: An infix fix
in thread An infix fix

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

Replies are listed 'Best First'.
Re^3: An infix fix
by Roy Johnson (Monsignor) on Mar 22, 2005 at 22:59 UTC
    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

        Scheme appears to be behaving as I described, returning operand values. It also has special behavior for no-argument cases. Note that (and 3) is not the same as (and 3 #t), so recursing down to the empty list will not emulate its behavior.

        I don't object to defining the zero-arguments case; I just object to using it as the basis for nonzero-argument cases. It is a special case:

        sub AND { @_ > 1 ? shift && AND(@_) : @_ ? shift : '#t'; }

        Caution: Contents may have been coded under pressure.
Re^3: An infix fix
by tlm (Prior) on Mar 22, 2005 at 23:05 UTC

    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.