Structural comparison in Standard ML

2019-07-11 04:26发布

问题:

I can't seem to find reference on why does this not work:

- (2000,1)<(2000,1);    
stdIn:18.1-18.18 Error: operator and operand don't agree [overload]
  operator domain: 'Z * 'Z
  operand:         (int * int) * (int * int)
  in expression:
    (2000,1) < (2000,1)

Does Standard ML support structural comparison?

回答1:

The short answer: Only for equality.

The strictly less than operator (<) in the top level environment is as the other comparison operators a bit "special". They are "special" in the way that they are (as the only ones) overloaded to work with both integers, reals, etc. Also the somewhat special thing about this overloading is that integer is used if a type can't be inferred (e.g., a polymorphic type was inferred 'a).

For the case of integers the Int.< function is used, which only takes two integers as argument

- Int.<;
val it = fn : int * int -> bool

However for equality, the case is a bit different, as seen by the type of the equality operator

- op=;
val it = fn : ''a * ''a -> bool

Here the polymorphic type is seen to bee ''a, note the double plings. This is because it can only be instantiated to an equality type (e.g., int, string, int'string, etc.). Note that real is not an equality type!

Update

The thing I normally do is to make a compare function for each (data)type i create. This way I have full control over what happens. The idea of the compare function is to return an order

datatype order = LESS | EQUAL | GREATER

With this you can easily make a case expression and do the appropriate thing, instead of a if .. < .. then .. else ..

Update1

Below code is from Andreas Rossberg's comment. I have included it here for easy reading

fun comparePair compareA compareB ((a1, b1), (a2, b2)) =
    case compareA (a1, a2) of
      EQUAL => compareB (b1, b2)
    | other => other

And some examples of use

- comparePair Int.compare String.compare ((2, "foo"), (3, "bar"));
val it = LESS : order
- comparePair Int.compare String.compare ((3, "bar"), (3, "bar"));
val it = EQUAL : order