[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: compare function return values



Sorry to elaborate on this already-long-discussed and not-so-important
subject, and thank you for the interesting elaboration of the comparison
value rationale in the revised version of the SRFI.

There is an interesting new argument there against the usage of symbols,
which relates to the mutual compares of the compare values themselves.
I'd like to think about the possible uses of such operations.

For the most general case, (compare (compare a b) (compare c d)), I find
it hard to come up with any use with.  There is the simple case where
the result is 0, where we can use eq(v)? and it means that a and b are
equally related as c and d.  Perhaps somebody can make some use for
that.  But the case that the value is 1 is true in these cases:
{ a = b and c < d; a > b and c < d; a > b and c = d }.  I'd like to see
the wizard that comes up with some use for this.  Equal considerations
apply for -1:

	a < b	a = b	a > b
c < d	 0	 1	 1
c = d	-1	 0	 1
c > d	-1	-1	 0

So, how about the not-so-general case where some of the four possible
arguments are the same?  For two distinct values, any sensible result
can be more elegantly expressed as a simple comparison; so how about the
cases of three distinct values?

Expressions like (compare (compare a a) (compare b c)) don't make sense,
as (compare a a) is a constant.  OTOH, changing the order of compare's
arguments just changes the sign.  So the only expression we have to look
at is:

(compare (compare a b) (compare b c))

ordering	value	ordering	value	ordering	value

a = b = c	0	a < b = c	-1	a < b < c	0
                        b = c < a	1       b < a < c	1
                        c < a = b	-1      a < c < b	-1
                        a = b < c	1       b < c < a	1
                        a = c < b	-1      c < a < b	-1
                        b < a = c	1       c < b < a	0

The useful cases seem to be those where value is 0, and the operation is
implementable by eq(v)?.  The cases where value is 1 are those where b =
(min a b c), and the cases where value is -1 are those where b = (max a
b c).  Again, this check can be made more elegantly by explicitly
testing b against a and c, and usage of (compare (compare a b) (compare
b c)) should IMO be discouraged (by declaring its return value to be a
symbol, for instance.)

It seems more and more to me that these handy ways of using the return
value of a comparison as a number, not a tag, leads to messy and
difficult-to-understand code.  For example, the "good" side of integers,
ability to reflect the comparison algorithmically by (* sign (compare a
b)), would probably be better (and more Scheme-like) handled by
something user-defined like (comparison-transform transformation
(compare a b)).  The construct (* sign (compare a b)) makes it look like
comparison transformations (sign e {-1, 1}) and comparison values
((compare a b) e {-1, 0, 1}) were closely related, which they are not.
If they were, (* (compare a b) (compare c d)) would make something
sensible, but instead it raises an asymmetry, for -1 acts as a reversion
value, whereas 1 acts as identity (as comparison values, they should act
"symmetrically").

So, _please_ still consider using symbols.  If the need to quote symbols
is too cumbersome (??!), please consider the special data type with #<,
#>, #= as the values.

As a last remark (which will probably earn me some yelling): while the
comparison values {-1, 0, 1} are not semantically sensible to use as
numbers, the comparison values {<, =, >} are semantically sensible to
use for building programs dynamically.  :)

Panu

-- 
personal contact: atehwa@xxxxxx, +35841 5323835, +3589 85619369
work contact: pkalliok@xxxxxxxxxxxxxxxx, +35850 3678003
kotisivu (henkkoht):	http://www.iki.fi/atehwa/
homepage (technical):	http://sange.fi/~atehwa/