Search code examples
smlmlcomparison-operators

Structural comparison in Standard ML


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?


Solution

  • 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