大于(和等效)期权的行为

时间:2018-09-07 10:04:33

标签: f# comparison optional

我正在为图像处理任务做一些事情(这里无关紧要),我偶然发现F#的Option类型的行为使我感到惊讶,因为它执行了大于(>)的比较。我找不到任何能直接解释我对Stack Overflow,F#文档或更广泛的网络应该有什么期望的内容(下文中有更多内容)。

我正在查看的特定部分类似于:

let sort3Elems (arr: byte option []) = 
    if arr.[0] > arr.[1] then swap &arr.[0] &arr.[1]
    if arr.[1] > arr.[2] then swap &arr.[1] &arr.[2]
    if arr.[0] > arr.[1] then swap &arr.[0] &arr.[2]

我将在其中传递四个字节选项的数组(如果您想知道为什么这看起来很奇怪并且超级无法使用,现在我刻意尝试重新实现一个非功能性语言实现教科书中的算法)。我原以为这会导致编译器错误,它会抱怨无法直接比较选项。令我惊讶的是,这种编译很好。出于好奇,我在F#Interactive中对其进行了测试,其结果如下所示:

let arr: byte option [] = Array.zeroCreate 4;;
val arr : byte option [] = [|None; None; None; None|]

> arr.[0] <- Some(127uy);;
val it : unit = ()

> arr.[2] <- Some(55uy);;
val it : unit = ()

> arr.[0] > arr.[2];;
val it : bool = true

> arr.[0] < arr.[2];;
val it : bool = false

> arr.[0] < arr.[1];;
val it : bool = false

> arr.[0] > arr.[1];;
val it : bool = true

> arr.[2] > arr.[1];;
val it : bool = true

> arr.[3] > arr.[1];;
val it : bool = false

> arr.[3] < arr.[1];;
val it : bool = false

> arr.[3] > arr.[1];;
val it : bool = false

在我看来,本质上,比较运算符在询问Some是否大于(小于)None时必须始终返回true(false),两个None总是返回false,并且两个包含类型相同的Somes比较包含的内容值(假设可以想象得到)。这很有意义,尽管我很惊讶。

想要确认这一点,我试图找到可以解释我所期望的行为的内容,但是找不到能解决问题的内容。 Option page in the MS F# Guide docs没有提及它,我在F#之类的地方找不到任何乐趣和利润。我什至无法在MS API文档中的任何地方找到有关Option的页面...看the source for Option in the F# GitHub repo并没有告诉我任何事情。我能找到的最好的是几年前的a blog post by Don Syme,但实际上并没有回答我的问题。有少量的堆栈溢出问题,讨论了与比较运算符或Option类型有关的主题,但我发现没有什么可以处理两者的组合。

所以,我的问题是,对Option类型进行大于/小于比较是否返回我上面推测的结果?我猜想这是F#程序员之间的常识,但这对我来说是个新闻。作为一个子问题/相关问题,有人知道我应该/应该在哪里寻求更多信息吗?谢谢。

1 个答案:

答案 0 :(得分:8)

F#编译器会自动为已区分的并集和记录类型生成比较。由于option只是一个有区别的工会,因此这也意味着您可以自动比较工会。我不确定是否有一个很好的网页来对此进行记录,但是您可以在section 8.15.4 in the F# specification中找到说明:

  

8.15.4生成的CompareTo实现的行为

     

对于类型T,生成的System.IComparable.CompareTo实现的行为如下:   如下:

     
      
  • 将y参数转换为类型T。如果转换失败,请引发InvalidCastException。
  •   
  • 如果T是引用类型且y为空,则返回1。
  •   
  • 如果T是结构或记录类型,请在每个对应的对上调用FSharp.Core.Operators.compare   按声明顺序排列x和y的字段,并返回第一个非零结果。
  •   
  • 如果T是联合类型,请首先在联合案例的索引上调用FSharp.Core.Operators.compare   取两个值,然后在每个对应的字段对x和y上对由   工会案。返回第一个非零结果。
  •   

如最后一个案例所述,选项的案例首先将案例进行比较。 None的索引小于Some,因此None的值将始终小于任何Some的值。如果大小写匹配,则根据None = NoneSome n比较Some mnm