Preamble: In most C-inspired programming languages, comparisons such as 3 < 2 < 1 would produce a slightly unsettling true result. This is because it's evaluated as (3 < 2) < 1, and 3 < 2, being false, numifies to 0. Whilst thinking upon this, a possible solution came to me...
Consider the comparison $x OP $y (where OP is one of (<|>|<=|>=|==|!=)). If $x is undef, or the comparison is false, it should return undef. Otherwise, it should return a true value that is numerically equivalent to $y ($y or "0 but true", as necessary).
This returned value will then become the LHS of the next comparison. If it is undef, that will propogate, giving an overall false result. Otherwise, it will be the correct number, as seen on the immediate LHS of this new comparison in the source code.
I have hacked a module to this effect together in perl, through extensive use of use overload;.
Unfortunately, perl's syntax does not allow you to chain together comparisons, even if they _are_ overloaded, so I have used the bitshift operators in their place. In true domino style, this has resulted in my having to omit the "*-or-equal" operators, as <<= and >>= (1) are right-associative and (2) must have an lvalue (ie not a constant) on their RHS.
Regardless of all that, here's a first draft of that module (beware: dangerously uncommented code follows):
[ UPDATE: taking diotalevi's comments into account ]
package ChainComparable; use strict; use UNIVERSAL (); sub new { my $class = shift; # allow for returning either a list or a scalar return wantarray ? (map { my $i = $_; bless \$i, $class } @_) : (bless \shift, $class); } sub comparison { # whee, currying my $sub = shift; return sub { my ($a, $b, $swap) = @_; $a = $$a; # allow for comparisons between two instances of this class $b = $$b if UNIVERSAL::isa($b, __PACKAGE__); # put the args in the right order ($a, $b) = ($b, $a) if $swap; if (defined $a and $sub->($a, $b)) { if ($b != 0) { return __PACKAGE__->new($b) } else { return __PACKAGE__->new("0 but true") } } else { return __PACKAGE__->new(undef) } }; } use overload ( bool => sub { $$_[0] }, '""' => sub { $$_[0] }, "0+" => sub { $$_[0] }, "==" => comparison(sub { $_[0] == $_[1] }), "!=" => comparison(sub { $_[0] != $_[1] }), "<<" => comparison(sub { $_[0] < $_[1] }), ">>" => comparison(sub { $_[0] > $_[1] }), );
Thoughts?
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: numbers with chainable comparisons
by diotalevi (Canon) on Jan 18, 2006 at 22:43 UTC | |
Re: numbers with chainable comparisons
by Anonymous Monk on Jan 18, 2006 at 23:38 UTC | |
by Courage (Parson) on Jan 19, 2006 at 18:19 UTC | |
by Anonymous Monk on Jan 19, 2006 at 22:12 UTC | |
by Irrelevant (Sexton) on Jan 19, 2006 at 09:44 UTC | |
Re: numbers with chainable comparisons
by jdporter (Paladin) on Jan 19, 2006 at 14:57 UTC | |
by Irrelevant (Sexton) on Jan 20, 2006 at 09:56 UTC | |
Re: numbers with chainable comparisons
by Roy Johnson (Monsignor) on Jan 19, 2006 at 15:57 UTC |