【发布时间】:2017-09-13 07:04:14
【问题描述】:
对于 F# 初学者来说,common surprise 是一个不完全匹配的事实:
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 中提供的类型。
【问题讨论】:
标签: f# pattern-matching guard-clause