Option的行为大于(和等价)

问题描述 投票:4回答:1

我正在为一个图像处理任务工作(这里并没有太大的相关性),我偶然发现F#的Option类型的行为让我感到惊讶,因为它执行了大于(>)的比较。在Stack Overflow,F#docs或更广泛的网络上,我找不到任何直接解释我应该期待的东西(下面有更多内容)。

我正在看的具体部分看起来像:

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),两个Nones总是返回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,它实际上没有回答我的问题。有一些Stack Overflow问题讨论了与比较运算符或Option类型相关的主题,但我没有发现任何涉及两者组合的问题。

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

f# comparison optional
1个回答
8
投票

F#编译器自动为区分的联合和记录类型生成比较。由于选项只是一个有区别的联合,这也意味着您可以自动比较联合。我不确定是否有一个很好的网页记录这个,但你可以在section 8.15.4 in the F# specification找到一个描述:

8.15.4 Behavior of the Generated CompareTo Implementations

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

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

如最后一个案例所述,选项案例首先比较案例。 None的指数小于Some,所以None值总是小于任何Some值。如果案例匹配,那么None = NoneSome nSome m将根据nm进行比较。

© www.soinside.com 2019 - 2024. All rights reserved.