f# - 当两个模式共享一个 `when` 子句时不完整的模式匹配

标签 f# pattern-matching guard-clause

common surprise对于刚入门的 F# 程序员来说,以下是不完全匹配的事实:

let x, y = 5, 10
match something with
| _ when x < y -> "Less than"
| _ when x = y -> "Equal"
| _ when x > y -> "Greater than"

但我刚刚遇到了一个让我感到惊讶的情况。下面是一小段示例代码来演示它:
type Tree =
| Leaf of int
| Branch of Tree list

let sapling = Branch [Leaf 1]  // Small tree with one leaf
let twoLeafTree = Branch [Leaf 1; Leaf 2]

let describe saplingsGetSpecialTreatment tree =
    match tree with
    | Leaf n
    | Branch [Leaf n] when saplingsGetSpecialTreatment ->
        sprintf "Either a leaf or a sapling containing %d" n
    | Branch subTree ->
        sprintf "Normal tree with sub-tree %A" subTree

describe true sapling // Result: "Either a leaf or a sapling containing 1"
describe false sapling // Result: "Normal tree with sub-tree [Leaf 1]"
describe true twoLeafTree // Result: "Normal tree with sub-tree [Leaf 1; Leaf 2]"
describe false twoLeafTree // Result: "Normal tree with sub-tree [Leaf 1; Leaf 2]"

此版本describe函数产生了“不完整的模式匹配此表达式”警告,即使模式匹配实际上是完整的。没有可能的树不会被该模式匹配匹配,这可以通过删除具有 when 的匹配的特定分支来看到。其中的表达:
let describe tree =
    match tree with
    | Leaf n -> sprintf "Leaf containing %d" n
    | Branch subTree ->
        sprintf "Normal tree with sub-tree %A" subTree

此版本describe返回 sapling 的“普通树”字符串和 twoLeafTree树木。

match的情况下表达式只包含 when表达式(如第一个示例,其中比较 xy),F# 编译器可能无法判断匹配是否完整是合理的。毕竟xy可能是具有“奇怪”的比较和相等实现的类型,其中这三个分支都不为真。*

但在像我这样的情况下 describe函数,为什么 F# 编译器不查看模式,说“如果所有 when 表达式计算为 false ,仍然会有完整匹配”并跳过“不完整模式匹配”警告?此处显示此警告是否有某些特定原因,还是只是 F# 编译器在这里有点简单并由于其代码不够复杂而给出误报警告的情况?

* 其实可以设置xy值使得 x < y , x = y , 和 x > y都是假的,没有超出标准 .Net 类型系统的“正常”范围。作为特别奖励问题/谜题,x 的这些值是多少?和 y ?不需要自定义类型来回答这个难题;您所需要的只是标准 .Net 中提供的类型。

最佳答案

在 F# match语法,when守卫适用于在它之前列举的所有情况,而不仅仅是最后一个。

在您的特定场景中,守卫 when saplingsGetSpecialTreatment适用于两者 Leaf nBranch [Leaf n]案件。因此,对于 tree = Leaf 42 && saplingsGetSpecialTreatment = false 的情况,此匹配将失败。

以下将是完整的,因为 Leaf case 现在有自己的分支:

let describe saplingsGetSpecialTreatment tree =
    match tree with
    | Leaf n ->
        sprintf "Either a leaf or a sapling containing %d" n
    | Branch [Leaf n] when saplingsGetSpecialTreatment ->
        sprintf "Either a leaf or a sapling containing %d" n
    | Branch subTree ->
        sprintf "Normal tree with sub-tree %A" subTree

关于f# - 当两个模式共享一个 `when` 子句时不完整的模式匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43455264/

相关文章:

python - 匹配 lib2to3 的 1-or-2-arg 函数调用的模式

haskell - 左箭头 <- 在 do block 之外是什么意思?

.net - 有没有办法四舍五入到小数点前 .net 中的 3 个有效数字(特别是 f#)?

f# - F# List.scan 中的初始状态

F# 写入文件更改返回类型的行为

f# - 将 COM DLL 与 FSI 结合使用

java - 使用模式匹配算法进行入侵检测

scala - Play 2.0 模板 - Scala `match` 和 `val` 不在 View 模板中编译

f# - 结合类型测试和文字的模式

ruby - 提前返回 vs if 在 ruby​​ 代码中