【问题标题】:Behaviour of greater than (and equivalent) for Option大于(和等效)选项的行为
【发布时间】:2018-09-07 10:04:33
【问题描述】:

我正在为图像处理任务做一些事情(在这里并没有太大的相关性),我偶然发现了 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,它实际上并没有回答我的问题。有一些 Stack Overflow 问题讨论了与比较运算符或选项类型有关的主题,但我没有找到任何涉及两者组合的问题。

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

【问题讨论】:

    标签: f# comparison optional


    【解决方案1】:

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

    8.15.4 生成的 CompareTo 实现的行为

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

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

    如最后一个案例中所述,选项的案例首先比较案例。 None 的索引小于Some,因此None 值将始终小于任何Some 值。如果案例匹配,则基于nm 比较None = NoneSome nSome m

    【讨论】:

    • 哇,来自 the Tomas Petricek 的回答。我真的应该考虑查看规范。谢谢您的回答! :)
    • @Jarak - 老实说,在网上找不到很好的参考资料后,我才想到自己查看规范 :-)
    猜你喜欢
    • 2017-07-30
    • 1970-01-01
    • 1970-01-01
    • 2018-01-17
    • 2018-01-04
    • 1970-01-01
    • 2015-09-16
    • 1970-01-01
    • 2019-01-31
    相关资源
    最近更新 更多