structural comparison of variants

2019-07-02 20:51发布

问题:

I want to deal with limits on the integer number line. I would like to have Pervasives.compare treat RightInfinity > Point x for all x, and the inverse for LeftInfinity.

In the ocaml REPL:

# type open_pt = LeftInfinity | Point of int | RightInfinity
  ;;
# List.sort Pervasives.compare [LeftInfinity; Point 0; Point 1; RightInfinity]
  ;;
- : open_pt list = [LeftInfinity; RightInfinity; Point 0; Point 1]

but

# type open_pt = LeftInfinity | Point of int | RightInfinity of unit
  ;;
# List.sort Pervasives.compare [LeftInfinity; Point 0; Point 1; RightInfinity ()]
  ;;
- : open_pt list = [LeftInfinity; Point 0; Point 1; RightInfinity ()]

"The perils of polymorphic compare" says

Variants are compared first by their tags, and then, if the tags are equal, descending recursively to the content.

Can one rely on any relationship between the order in which variants appear in a type declaration and the order of the tags?

回答1:

No, you should not rely on that. You should define your own comparison function. Of course, that means you'll have to lift it through datastructures (to be able to compare, say, lists of open_pt), but that's the safe thing to do when you want a domain-specific comparison function.

Note that extended standard libraries such as Batteries or Core provide auxiliary functions to lift comparisons through all common datastructures, to help you extend your domain-specific comparison to any type containing an open_pt.

Edit: Note that you can rely on that, as the ordering of non-constant constructors is specified in the OCaml/C interface. I don't think that's a good idea, though -- what if you need to put closures inside your functor argument type next time?



标签: compare ocaml