对于 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
表达式的情况下(如第一个示例,其中x
和y
正在被比较),F# 编译器可能无法判断匹配是否完成是合理的。毕竟,x
并且y
可能是具有比较和相等的“奇怪”实现的类型,其中这三个分支都不为真。 *
但是在像我的describe
函数这样的情况下,为什么 F# 编译器不查看模式,说“如果所有when
表达式评估为false
,仍然会有完全匹配”并跳过“不完全模式匹配”警告?此处出现此警告是否有某些特定原因,或者只是 F# 编译器在这里有点简单化并给出误报警告,因为它的代码不够复杂?
* 事实上,可以设置x
和y
的值,使x < y
、x = y
和x > y
都为假,而不会超出标准 .Net 类型系统的“正常”界限。x
作为一个特殊的奖励问题/谜题,和的这些值是y
什么?不需要自定义类型来回答这个难题;您所需要的只是标准.Net 中提供的类型。