Chaining comparison operators

作者:   發佈於:   #perl #raku #python3

The syntax of chaining multiple comparisons is pretty common in mathmatics, with one expression such as $a < $b < $c, the relation of multiple variables are described. It is not commonly seen in programming languages though.

Raku (formly, Perl6) supports this syntax since the very beginning. As an example program, num-within, which is designed to read numbers from STDIN and echo them back if and only if they are within the range $from...$until:

#!/usr/bin/env raku
## Usage: num-within <from> <until>

my ($from, $until) = @*ARGS[0, 1];

for $*IN.lines() -> $num {
    if $from <= $num < $until {
        say $num
    }
}

Used like this:

# bash -c 'while true; do echo $RANDOM; done' | num-within 100 120
114
165
155
130
161
199
108
115
153
166
...

Python3 also supports comparison chaining. Here's the same program in python3:

#!/usr/bin/env python3
## Usage: num-within.py <from> <until>

import sys

num_from  = int(sys.argv[1])
num_until = int(sys.argv[2])

for line in sys.stdin:
    n = int(line)
    if num_from <= n < num_until:
        print(str(n))

Recently Perl5 started to partially support comparison chaining since version 5.31.10, and latter 5.32.0. Here's num-within in Perl5:

#!/usr/bin/env perl
## Usage: num-within.pl <from> <until>
use v5.31.10;

my ($from, $until) = @ARGV[0,1];

while(defined(my $num = <STDIN>)) {
    if ($from <= $num < $until) {
        print $num;
    }
}

Obviously there are many other usages than just checking the boundary of a given variable. max3(a,b,c) would be a good example (take the maximum out of 3 values):

sub max3($x, $y, $z) {
    return $x if $y <= $x >= $z;
    return $y if $z <= $y >= $z;
    return $z;
}

However, the implementation in Perl5 at the moment is still less ideal. Considering this expression:

$a < $b == $c < $d

... express the same meaning in Raku, Python3, and in math, which is:

($a < $b) and ($b == $c) and ($c < $d)

On the other hand, in Perl5, it is currently logically equivalent to this:

($a < $b) == ($c < $d)

This descrepancy is due to the fact that == operator in Perl5 cannot be one part of a comparison chain, which is actually documented in perlop since perl-5.31.11. (Arguabaly not directly documented, but could be derived from the precedance table.) Perhaps we need to wait a little bit longer.


本文為 連環比較運算式 一文之英文版。