考虑以下无意义的lambda:
function
| [] -> "Empty list"
| hd::tl -> "Not so empty list"
这很好用。现在我按如下方式重写它:
function
| [] -> "Empty list"
| hd::tl & l -> "Not so empty list"
同样,出于无意义的原因(我知道我可以通过使用as
代替&
来达到相同的效果,但这一切都与代码高尔夫问题有关,而这与我们无关这个问题)。现在F#编译器告诉我:
警告FS0025:此表达式上的不完整模式匹配。对于 例如,值'[]'可能表示未涵盖的案例 图案(多个)。
这没有任何意义 - 我在第一条规则中明确处理[]
的情况。关于[]
,我没有看到从第一个函数到第二个函数的变化;函数的第二个规则都不匹配它,但只有第二个函数给出警告。我所做的只是添加一个匹配任何的其他模式。
当然,使用空列表调用第二个函数确实成功。
是否有正确的理由发生此警告,或者F#模式验证是否只是有一些怪癖?当使用更高级的模式时,我可以看到有这样的情况,但这似乎是一个非常基本的模式。即使问题一般无法解决,似乎这种类型的情况也足够普遍,值得在编译器中进行特殊处理。
答案 0 :(得分:6)
我认为F#编译器在这种情况下是实用的。
最后,第二条规则可以表示为对输入列表xs
的约束:
xs = hd :: tl && xs = l
F#编译器似乎没有探索&&
约束。这是合理的,因为约束可以是任意复杂的,&
的使用是非常罕见的。
partial active patterns我们遇到了类似的问题:
let (|Empty|_|) = function
| [] -> Some()
| _ -> None
let (|NonEmpty|_|) = function
| _ :: _ -> Some()
| _ -> None
// warning FS0025
let f = function
| Empty -> "Empty list"
| NonEmpty -> "Not so empty list"
要解决此问题,您可以:
as
代替&
,这更合适,因为l
只是一种约束力。在末尾添加通配符模式以消除警告。我经常写
let f =
function
| hd::tl & l -> "Not so empty list"
| _ -> "Empty list"
使用nowarn "25"
。
答案 1 :(得分:4)
我猜你发现了另一个案例(除了when
子句和部分活动模式之外)编译器的决策过程不够强大。 (这就是为什么警告信息显示可能表示: - ))。
如果你想在没有警告的情况下获得相同的功能,那么你可以使用这样一个完整的活动模式(但实际上,对于列表,我可能只需要_
作为空列表案例@ @垫建议):
let (|Empty|NonEmpty|) l =
match l with [] -> Empty | x::xs -> NonEmpty(x, xs, l)
let foo = function
| Empty -> 0
| NonEmpty(x, xs, l) -> 1