Changing ==,>,<, etc

The latest Perl exegesis
(http://www.perl.com/pub/a/2003/07/29/exegesis6.html?page=4)
introduces “junction types”, which are really cool.
In short, you can do expressions like (a == any(1,2,3)) or (a >
all(1,2,3)) instead of (a == 1) or (a == 2) or (a == 3), etc.

So of course, I immediately set out to do this in ruby. So, I whipped
up a Disjunction class, and the any() function for syntactic sugar,
and soon I could do:

1 == any(1,2,3)

true

4 == any(1,2,3)

false

And all was well. But then I hit a snag:

1 < any(1,2,3)

ERR: (eval):1:in `<’: Disjunction can’t be coerced into Fixnum

Fixnum#== seems to be smart enough to call Disjunction#==, which gets
the behavior I want. Unfortunately, Fixnum#< is not, and neither are
most of the <,>,== methods in the various built-in classes (i.e.
String#== and Array#== both return false for any Junction class).

Of course, with ObjectSpace and module_eval, I can redefine everyone’s
comparison methods to work properly, but this is kind of ugly. Also,
if someone defines a new class after after I have done my ObjectSpace
hack, they have to explicitly write their comparison methods to know
about Junctions.

Is there a better way to do this?

If there’s not a better way, should there be?
I was thinking that perhaps all comparison methods should have a
similar semantics, along the lines of:

class Foo
def ==(obj)
if obj.is_a?(Foo)
#I know how to compare myself to other Foo objects,
#so I will do so
return somevalue
else
#I don’t know how to compare myself to non-Foo objects,
#but maybe they know how to compare themselves to me –
#let’s give them a chance
return (obj == self)
end
end
end

Or at least, that’s the basic idea. There also needs to be some way to
bail out when neither class knows how to compare to the other –
either by returning false or throwing an exception.

If all comparison methods worked this way, I could implement my
Junction classes with no hacks, since objects that didn’t know
anything about Junctions would just let the Junction do the
comparison.

What you want can be done with the any? method for arrays.

[1, 2, 3].any? { |e| 1 < e }

There’s also an all? method.

The following container (or container-like) classes have both the any?
and all? methods: Array, Hash, Range, String, Set.

Regards,

Mark

···

On Thursday, July 31, 2003, at 02:22 PM, Nathan Weston wrote:

[snip]
And all was well. But then I hit a snag:

1 < any(1,2,3)

ERR: (eval):1:in `<': Disjunction can’t be coerced into Fixnum

[snip some very interesting questions I intend to think about.]

I think I have an idea. I’m not sure about the implementation details:

Example: 3 < any(1,2,4)

  1. Create a Disjunction#<=> and mixin Enumerable so that you can write
    things like:

    any(3) < any(1,2,4)
    all(3) > any(1,2,4)

  2. Create a Disjunction#coerce method so that the line:
    3 < any(1,2,4)
    Is turned into the line:
    all(3) > any(1,2,4) # It doesn’t matter if it’s any(3) or all(3).

When Ruby sees “3 < any(1,2,4)” it’ll look for Fixnum#coerce for help.
When it doesn’t help, it’ll look at Disjunction#coerce. Or, at least
that’s what I think.

The Disjunction#coerce would be written somewhat like this:

class Disjunction
# WARNING: No error checking.
def coerce(other)
return all(other), self
end
end

Cheers,
Daniel.

···

On Fri, Aug 01, 2003 at 03:22:36AM +0900, Nathan Weston wrote:

The latest Perl exegesis
(Exegesis 6)
introduces “junction types”, which are really cool.
In short, you can do expressions like (a == any(1,2,3)) or (a >
all(1,2,3)) instead of (a == 1) or (a == 2) or (a == 3), etc.

So of course, I immediately set out to do this in ruby. So, I whipped
up a Disjunction class, and the any() function for syntactic sugar,
and soon I could do:

1 == any(1,2,3)

true

4 == any(1,2,3)

false

And all was well. But then I hit a snag:

1 < any(1,2,3)

ERR: (eval):1:in `<': Disjunction can’t be coerced into Fixnum

Fixnum#== seems to be smart enough to call Disjunction#==, which gets
the behavior I want. Unfortunately, Fixnum#< is not, and neither are
most of the <,>,== methods in the various built-in classes (i.e.
String#== and Array#== both return false for any Junction class).

Of course, with ObjectSpace and module_eval, I can redefine everyone’s
comparison methods to work properly, but this is kind of ugly. Also,
if someone defines a new class after after I have done my ObjectSpace
hack, they have to explicitly write their comparison methods to know
about Junctions.

Is there a better way to do this?

If there’s not a better way, should there be?
I was thinking that perhaps all comparison methods should have a
similar semantics, along the lines of:

class Foo
def ==(obj)
if obj.is_a?(Foo)
#I know how to compare myself to other Foo objects,
#so I will do so
return somevalue
else
#I don’t know how to compare myself to non-Foo objects,
#but maybe they know how to compare themselves to me –
#let’s give them a chance
return (obj == self)
end
end
end

Or at least, that’s the basic idea. There also needs to be some way to
bail out when neither class knows how to compare to the other –
either by returning false or throwing an exception.

If all comparison methods worked this way, I could implement my
Junction classes with no hacks, since objects that didn’t know
anything about Junctions would just let the Junction do the
comparison.


Daniel Carrera | PGP: 6643 8C8B 3522 66CB D16C D779 2FDD 7DAC 9AF7 7A88
Math PhD. UMD | http://www.math.umd.edu/~dcarrera/pgp.html

          • Weekly Smile * * * * * * * * * * * * * * * * * * * * * * * *
            Sign in a hotel in Athens:
            Visitors are expected to complain at the office between the hours
            of 9 and 11 A.M. daily.

1 < any(1,2,3)

What you want can be done with the any? method for arrays.

[1, 2, 3].any? { |e| 1 < e }

But the syntax “1 < any(1,2,3)” is very readable.


Daniel Carrera | PGP: 6643 8C8B 3522 66CB D16C D779 2FDD 7DAC 9AF7 7A88
Math PhD. UMD | http://www.math.umd.edu/~dcarrera/pgp.html

          • Weekly Smile * * * * * * * * * * * * * * * * * * * * * * * *
            Sign in a hotel in Athens:
            Visitors are expected to complain at the office between the hours
            of 9 and 11 A.M. daily.

any? and all? are very receiver-centric - compare

a.any? {|i| b.all? {|j| i < j} }

with

any(a) < all(b)

The latter shows up the symmetry a lot more clearly - I’ve always hated
having to write nested loops to express something flat.

martin

···

Mark Wilson mwilson13@cox.net wrote:

On Thursday, July 31, 2003, at 02:22 PM, Nathan Weston wrote:

[snip]
And all was well. But then I hit a snag:

1 < any(1,2,3)

ERR: (eval):1:in `<': Disjunction can’t be coerced into Fixnum

[snip some very interesting questions I intend to think about.]

What you want can be done with the any? method for arrays.

[1, 2, 3].any? { |e| 1 < e }

There’s also an all? method.

That seems to work for Numeric types, but it doesn’t help with other
objects (Strings, for example).
I’d like to be able to put any object inside a Disjunction or
Conjunction.

BTW, I am using ruby 1.6.8. Are there any relevant differences in 1.8?

Nathan

Daniel Carrera dcarrera@math.umd.edu wrote in message news:20030731184328.GB1297@math.umd.edu

···

I think I have an idea. I’m not sure about the implementation details:

Example: 3 < any(1,2,4)

  1. Create a Disjunction#<=> and mixin Enumerable so that you can write
    things like:

    any(3) < any(1,2,4)
    all(3) > any(1,2,4)

  2. Create a Disjunction#coerce method so that the line:
    3 < any(1,2,4)
    Is turned into the line:
    all(3) > any(1,2,4) # It doesn’t matter if it’s any(3) or all(3).

When Ruby sees “3 < any(1,2,4)” it’ll look for Fixnum#coerce for help.
When it doesn’t help, it’ll look at Disjunction#coerce. Or, at least
that’s what I think.

The Disjunction#coerce would be written somewhat like this:

class Disjunction
# WARNING: No error checking.
def coerce(other)
return all(other), self
end
end

Cheers,
Daniel.

On Fri, Aug 01, 2003 at 03:22:36AM +0900, Nathan Weston wrote:

The latest Perl exegesis
(Exegesis 6)
introduces “junction types”, which are really cool.
In short, you can do expressions like (a == any(1,2,3)) or (a >
all(1,2,3)) instead of (a == 1) or (a == 2) or (a == 3), etc.

So of course, I immediately set out to do this in ruby. So, I whipped
up a Disjunction class, and the any() function for syntactic sugar,
and soon I could do:

1 == any(1,2,3)

true

4 == any(1,2,3)

false

And all was well. But then I hit a snag:

1 < any(1,2,3)

ERR: (eval):1:in `<': Disjunction can’t be coerced into Fixnum

Fixnum#== seems to be smart enough to call Disjunction#==, which gets
the behavior I want. Unfortunately, Fixnum#< is not, and neither are
most of the <,>,== methods in the various built-in classes (i.e.
String#== and Array#== both return false for any Junction class).

Of course, with ObjectSpace and module_eval, I can redefine everyone’s
comparison methods to work properly, but this is kind of ugly. Also,
if someone defines a new class after after I have done my ObjectSpace
hack, they have to explicitly write their comparison methods to know
about Junctions.

Is there a better way to do this?

If there’s not a better way, should there be?
I was thinking that perhaps all comparison methods should have a
similar semantics, along the lines of:

class Foo
def ==(obj)
if obj.is_a?(Foo)
#I know how to compare myself to other Foo objects,
#so I will do so
return somevalue
else
#I don’t know how to compare myself to non-Foo objects,
#but maybe they know how to compare themselves to me –
#let’s give them a chance
return (obj == self)
end
end
end

Or at least, that’s the basic idea. There also needs to be some way to
bail out when neither class knows how to compare to the other –
either by returning false or throwing an exception.

If all comparison methods worked this way, I could implement my
Junction classes with no hacks, since objects that didn’t know
anything about Junctions would just let the Junction do the
comparison.


Daniel Carrera | PGP: 6643 8C8B 3522 66CB D16C D779 2FDD 7DAC 9AF7 7A88
Math PhD. UMD | http://www.math.umd.edu/~dcarrera/pgp.html

          • Weekly Smile * * * * * * * * * * * * * * * * * * * * * * * *
            Sign in a hotel in Athens:
            Visitors are expected to complain at the office between the hours
            of 9 and 11 A.M. daily.

What I like at this container based solution is that you can oversee
the overall complexity of the statement. Other solutions might require
more explicit knowledge about complexity issues.

Cheers
Sascha

···

Mark Wilson mwilson13@cox.net wrote:

What you want can be done with the any? method for arrays.

[1, 2, 3].any? { |e| 1 < e }

There’s also an all? method.

I’ve always favored an “in” operator as in Pascal
or (I think) Python. It would call include? just
as for/in calls each:

1 in [1,2,3] # means [1,2,3].include? 1

Hal

···

----- Original Message -----
From: “Daniel Carrera” dcarrera@math.umd.edu
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Thursday, July 31, 2003 1:46 PM
Subject: Re: Changing ==,>,<, etc

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

1 < any(1,2,3)

What you want can be done with the any? method for arrays.

[1, 2, 3].any? { |e| 1 < e }

But the syntax “1 < any(1,2,3)” is very readable.


Hal Fulton
hal9000@hypermetrics.com

It’s a block passed to an iterator – and not a loop :wink:

···

On Thursday, July 31, 2003, at 04:03 PM, Martin DeMello wrote:

[snip]

any? and all? are very receiver-centric - compare

a.any? {|i| b.all? {|j| i < j} }

with

any(a) < all(b)

The latter shows up the symmetry a lot more clearly - I’ve always hated
having to write nested loops to express something flat.
[snip]

How is your Disjunction class implemented? Does it understand Strings?
Can I type this?:

all(“c”) < any(“d”, “e”, “f”)

If so, then the Disjunction#coerce should work. If not, then the problem
is in the implementation of Disjunction I think.

Daniel.

···

On Fri, Aug 01, 2003 at 10:45:55AM +0900, Nathan Weston wrote:

That seems to work for Numeric types, but it doesn’t help with other
objects (Strings, for example).
I’d like to be able to put any object inside a Disjunction or
Conjunction.

BTW, I am using ruby 1.6.8. Are there any relevant differences in 1.8?

Nathan

Daniel Carrera dcarrera@math.umd.edu wrote in message news:20030731184328.GB1297@math.umd.edu

I think I have an idea. I’m not sure about the implementation details:

Example: 3 < any(1,2,4)

  1. Create a Disjunction#<=> and mixin Enumerable so that you can write
    things like:

    any(3) < any(1,2,4)
    all(3) > any(1,2,4)

  2. Create a Disjunction#coerce method so that the line:
    3 < any(1,2,4)
    Is turned into the line:
    all(3) > any(1,2,4) # It doesn’t matter if it’s any(3) or all(3).

When Ruby sees “3 < any(1,2,4)” it’ll look for Fixnum#coerce for help.
When it doesn’t help, it’ll look at Disjunction#coerce. Or, at least
that’s what I think.

The Disjunction#coerce would be written somewhat like this:

class Disjunction
# WARNING: No error checking.
def coerce(other)
return all(other), self
end
end

Cheers,
Daniel.

On Fri, Aug 01, 2003 at 03:22:36AM +0900, Nathan Weston wrote:

The latest Perl exegesis
(Exegesis 6)
introduces “junction types”, which are really cool.
In short, you can do expressions like (a == any(1,2,3)) or (a >
all(1,2,3)) instead of (a == 1) or (a == 2) or (a == 3), etc.

So of course, I immediately set out to do this in ruby. So, I whipped
up a Disjunction class, and the any() function for syntactic sugar,
and soon I could do:

1 == any(1,2,3)

true

4 == any(1,2,3)

false

And all was well. But then I hit a snag:

1 < any(1,2,3)

ERR: (eval):1:in `<': Disjunction can’t be coerced into Fixnum

Fixnum#== seems to be smart enough to call Disjunction#==, which gets
the behavior I want. Unfortunately, Fixnum#< is not, and neither are
most of the <,>,== methods in the various built-in classes (i.e.
String#== and Array#== both return false for any Junction class).

Of course, with ObjectSpace and module_eval, I can redefine everyone’s
comparison methods to work properly, but this is kind of ugly. Also,
if someone defines a new class after after I have done my ObjectSpace
hack, they have to explicitly write their comparison methods to know
about Junctions.

Is there a better way to do this?

If there’s not a better way, should there be?
I was thinking that perhaps all comparison methods should have a
similar semantics, along the lines of:

class Foo
def ==(obj)
if obj.is_a?(Foo)
#I know how to compare myself to other Foo objects,
#so I will do so
return somevalue
else
#I don’t know how to compare myself to non-Foo objects,
#but maybe they know how to compare themselves to me –
#let’s give them a chance
return (obj == self)
end
end
end

Or at least, that’s the basic idea. There also needs to be some way to
bail out when neither class knows how to compare to the other –
either by returning false or throwing an exception.

If all comparison methods worked this way, I could implement my
Junction classes with no hacks, since objects that didn’t know
anything about Junctions would just let the Junction do the
comparison.


Daniel Carrera | PGP: 6643 8C8B 3522 66CB D16C D779 2FDD 7DAC 9AF7 7A88
Math PhD. UMD | http://www.math.umd.edu/~dcarrera/pgp.html

          • Weekly Smile * * * * * * * * * * * * * * * * * * * * * * * *
            Sign in a hotel in Athens:
            Visitors are expected to complain at the office between the hours
            of 9 and 11 A.M. daily.


Daniel Carrera | PGP: 6643 8C8B 3522 66CB D16C D779 2FDD 7DAC 9AF7 7A88
Math PhD. UMD | http://www.math.umd.edu/~dcarrera/pgp.html

          • Weekly Smile * * * * * * * * * * * * * * * * * * * * * * * *
            Sign in a hotel in Athens:
            Visitors are expected to complain at the office between the hours
            of 9 and 11 A.M. daily.

Dnia czw 31. lipca 2003 22:03, Martin DeMello napisa³:

any? and all? are very receiver-centric - compare

a.any? {|i| b.all? {|j| i < j} }

with

any(a) < all(b)

The latter shows up the symmetry a lot more clearly - I’ve always hated
having to write nested loops to express something flat.

But there is no symmetry. Does it mean that there exists something in “a”
such that it’s smaller than everything in “b”, or that for everything in
“b” there exists a smaller thing in “a”?

Well, for “<” it happens to be equivalent because “<” is transitive; it’s
the same as a.min < b.min for non-empty “a” and “b”. What about “!=”?
Does any(1,2) != all(1,2)?

···


__("< Marcin Kowalczyk
__/ qrczak@knm.org.pl
^^ Blog człowieka poczciwego.

At the moment, Disjunction doesn’t know anything about its contents –
it just does

def ==(obj)
@contents.each { |c|
if c == obj
return true
end
}

return false
end

At the moment,
any(“1”, “2”, “3”) == “1” works fine.

But if I do the reverse:
“1” == any(“1”, “2”, “3”)

it just returns false. String#== doesn’t even try to call a coerce
method. String#< gives a type error, again without trying to call
Disjunction#coerce. Looking at the API docs, it seems that only
Numeric types have coerce.

Nathan

Daniel Carrera dcarrera@math.umd.edu wrote in message news:20030801021020.GA1643@math.umd.edu

···

How is your Disjunction class implemented? Does it understand Strings?
Can I type this?:

all(“c”) < any(“d”, “e”, “f”)

If so, then the Disjunction#coerce should work. If not, then the problem
is in the implementation of Disjunction I think.

Daniel.

On Fri, Aug 01, 2003 at 10:45:55AM +0900, Nathan Weston wrote:

That seems to work for Numeric types, but it doesn’t help with other
objects (Strings, for example).
I’d like to be able to put any object inside a Disjunction or
Conjunction.

BTW, I am using ruby 1.6.8. Are there any relevant differences in 1.8?

Nathan

Daniel Carrera dcarrera@math.umd.edu wrote in message news:20030731184328.GB1297@math.umd.edu

I think I have an idea. I’m not sure about the implementation details:

Example: 3 < any(1,2,4)

  1. Create a Disjunction#<=> and mixin Enumerable so that you can write
    things like:

    any(3) < any(1,2,4)
    all(3) > any(1,2,4)

  2. Create a Disjunction#coerce method so that the line:
    3 < any(1,2,4)
    Is turned into the line:
    all(3) > any(1,2,4) # It doesn’t matter if it’s any(3) or all(3).

When Ruby sees “3 < any(1,2,4)” it’ll look for Fixnum#coerce for help.
When it doesn’t help, it’ll look at Disjunction#coerce. Or, at least
that’s what I think.

The Disjunction#coerce would be written somewhat like this:

class Disjunction
# WARNING: No error checking.
def coerce(other)
return all(other), self
end
end

Cheers,
Daniel.

On Fri, Aug 01, 2003 at 03:22:36AM +0900, Nathan Weston wrote:

The latest Perl exegesis
(Exegesis 6)
introduces “junction types”, which are really cool.
In short, you can do expressions like (a == any(1,2,3)) or (a >
all(1,2,3)) instead of (a == 1) or (a == 2) or (a == 3), etc.

So of course, I immediately set out to do this in ruby. So, I whipped
up a Disjunction class, and the any() function for syntactic sugar,
and soon I could do:

1 == any(1,2,3)

true

4 == any(1,2,3)

false

And all was well. But then I hit a snag:

1 < any(1,2,3)

ERR: (eval):1:in `<': Disjunction can’t be coerced into Fixnum

Fixnum#== seems to be smart enough to call Disjunction#==, which gets
the behavior I want. Unfortunately, Fixnum#< is not, and neither are
most of the <,>,== methods in the various built-in classes (i.e.
String#== and Array#== both return false for any Junction class).

Of course, with ObjectSpace and module_eval, I can redefine everyone’s
comparison methods to work properly, but this is kind of ugly. Also,
if someone defines a new class after after I have done my ObjectSpace
hack, they have to explicitly write their comparison methods to know
about Junctions.

Is there a better way to do this?

If there’s not a better way, should there be?
I was thinking that perhaps all comparison methods should have a
similar semantics, along the lines of:

class Foo
def ==(obj)
if obj.is_a?(Foo)
#I know how to compare myself to other Foo objects,
#so I will do so
return somevalue
else
#I don’t know how to compare myself to non-Foo objects,
#but maybe they know how to compare themselves to me –
#let’s give them a chance
return (obj == self)
end
end
end

Or at least, that’s the basic idea. There also needs to be some way to
bail out when neither class knows how to compare to the other –
either by returning false or throwing an exception.

If all comparison methods worked this way, I could implement my
Junction classes with no hacks, since objects that didn’t know
anything about Junctions would just let the Junction do the
comparison.


Daniel Carrera | PGP: 6643 8C8B 3522 66CB D16C D779 2FDD 7DAC 9AF7 7A88
Math PhD. UMD | http://www.math.umd.edu/~dcarrera/pgp.html

          • Weekly Smile * * * * * * * * * * * * * * * * * * * * * * * *
            Sign in a hotel in Athens:
            Visitors are expected to complain at the office between the hours
            of 9 and 11 A.M. daily.


Daniel Carrera | PGP: 6643 8C8B 3522 66CB D16C D779 2FDD 7DAC 9AF7 7A88
Math PhD. UMD | http://www.math.umd.edu/~dcarrera/pgp.html

          • Weekly Smile * * * * * * * * * * * * * * * * * * * * * * * *
            Sign in a hotel in Athens:
            Visitors are expected to complain at the office between the hours
            of 9 and 11 A.M. daily.

No - this unrolls to

[1,2].any? {|i| [1,2].all? {|j| i != j}}

which is false.

The symmetry is highlighted by the other way to unroll it:

[1,2].all? {|j| [1,2].any? {|i| i != j}}

i.e., there is no reason the LHS should be in the outer loop, rather
than the RHS. My point was that the only reason there was an ‘outer
loop’ was that the language forces you to write loops nestedly, whereas
a cross product (essentially what this is) is flat.

The only asymmetry involved is the fact that you have to keep the loop
variables in their proper order with respect to the operator, function
or whatever (not evident here because != is commutative).

Also, any(1,2) != any(1,2) should be true.

martin

···

Marcin ‘Qrczak’ Kowalczyk qrczak@knm.org.pl wrote:

Dnia czw 31. lipca 2003 22:03, Martin DeMello napisa?:

any? and all? are very receiver-centric - compare

a.any? {|i| b.all? {|j| i < j} }

with

any(a) < all(b)

The latter shows up the symmetry a lot more clearly - I’ve always hated
having to write nested loops to express something flat.

But there is no symmetry. Does it mean that there exists something in “a”
such that it’s smaller than everything in “b”, or that for everything in
“b” there exists a smaller thing in “a”?

Well, for “<” it happens to be equivalent because “<” is transitive; it’s
the same as a.min < b.min for non-empty “a” and “b”. What about “!=”?
Does any(1,2) != all(1,2)?

Dnia ¶ro 17. wrze¶nia 2003 14:54, Martin DeMello napisa³:

i.e., there is no reason the LHS should be in the outer loop, rather
than the RHS. My point was that the only reason there was an ‘outer
loop’ was that the language forces you to write loops nestedly, whereas
a cross product (essentially what this is) is flat.

I disagree. It’s essential which is outer and which is inner unless
quantifiers happen to commute (both “any” or both “all”). The decision to
put LHS in the outer loop is arbitrary; if you wanted the other way you
must search for an operator with flipped arguments (which happens to be
easy among the six comparison operators).

Also, any(1,2) != any(1,2) should be true.

I wrote any(1,2) != all(1,2). And what about all(1,2) != any(1,2)?
If they are the same, then “any” and “all” must be treated with different
priority. If they are different, then != is no longer commutative.
(I suspect the latter.) Both cases are unintuitive for me.

···


__("< Marcin Kowalczyk
__/ qrczak@knm.org.pl
^^ Blog człowieka poczciwego.

Good point. I see now that it’s analogous to the fact that

(forall x)(there exists y)(x != y)

is different from

(there exists y)(forall x)(x != y)

So there is, indeed, as you pointed out, the notion of an inner and an
outer quantifier.

martin

···

Marcin ‘Qrczak’ Kowalczyk qrczak@knm.org.pl wrote:

Dnia ?ro 17. wrze?nia 2003 14:54, Martin DeMello napisa?:

i.e., there is no reason the LHS should be in the outer loop, rather
than the RHS. My point was that the only reason there was an ‘outer
loop’ was that the language forces you to write loops nestedly, whereas
a cross product (essentially what this is) is flat.

I disagree. It’s essential which is outer and which is inner unless
quantifiers happen to commute (both “any” or both “all”). The decision to
put LHS in the outer loop is arbitrary; if you wanted the other way you
must search for an operator with flipped arguments (which happens to be
easy among the six comparison operators).

Also, any(1,2) != any(1,2) should be true.

I wrote any(1,2) != all(1,2). And what about all(1,2) != any(1,2)?
If they are the same, then “any” and “all” must be treated with different
priority. If they are different, then != is no longer commutative.
(I suspect the latter.) Both cases are unintuitive for me.