变种的结构比较

3
我希望处理整数数轴上的限制。我希望Pervasives.compare能够处理所有x,使得RightInfinity > Point x,并且对于LeftInfinity反过来。
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]

但是
# 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 ()]

"多态比较的危险性"指出:

变量首先按照它们的标记进行比较,如果标记相等,则向下递归到内容。

在类型声明中变体出现的顺序与标记顺序之间是否存在任何关系?

1个回答

3
不,您不应该依赖它。您应该定义自己的比较函数。当然,这意味着您将通过数据结构来提升它(以能够比较,例如,列表中的 open_pt),但这是在您想要特定于域的比较函数时安全的做法。
请注意,扩展标准库(如 Batteries 或 Core)提供了辅助函数,通过所有常见的数据结构来提升比较,以帮助您将特定于域的比较扩展到包含 open_pt 的任何类型。
编辑:请注意,您可以依赖它,因为非常数构造函数的排序在 OCaml/C 接口中已指定。不过我认为这不是一个好主意——如果下一次您需要在函数器参数类型中放置闭包呢?

是的,我知道类型应该封装它们的语义,但我想将此类型用作另一个模块的参数,该模块在多个意义上使用二进制比较运算符,而我不希望小改变变成大问题。 - Mike Samuel
过度依赖多态比较运算符是OCaml编程中惯用的严重错误之一。 - gasche
我坚持使用我惯用的OCaml!;-) 但是,在使用多态比较时,我从未遇到过需要依赖标签排序方式的情况,只需要依赖顺序的完整性(线性)。也许在这种情况下,多态运算符不会浮现在脑海中。 - lukstafi
@lukstafi:确实,我认为最好只使用Pervasives.compare作为“我不想被打扰”的方式来获得完全排序,例如用于唯一性或树平衡。我认为开始依赖此比较的语义(例如对于成对的词汇编排或反向词汇编排?)是一个相当可疑的想法。但第一种情况也与数据类型的演变(闭包、对象等)相对脆弱。 - gasche
@gasche,是的。我在问题中提供的链接“多态比较的危险”认为,如果标签的顺序是已知且可操作的,那么可以设计类型使其在多态比较中表现良好。显然,当像Set.t这样的基于树的数据结构需要急切地进行规范化时,这并不总是可行的,因为代价太高。但是有一些类型是可能的,并且也很有用。 - Mike Samuel
@MikeSamuel:考虑到您对合理(但有时更痛苦)方式的适应能力,我编辑了我的消息,并提供了更多信息,表明确实可以根据声明顺序进行推理。 - gasche

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接