我正在如下功能中使用模式匹配:
let rec calculate : Calculation<MyType> -> MyVO -> Calculation<MyType list>=
fun c l ->
fun arrayA arrayC ->
myComputationExpression {
if arrayA.Length<>arrayC.Length then
yield! l
else
match arrayA, arrayC with
| [], [] -> yield! C
| [a], [c] -> yield! calculate a c
| headA :: tailA, headC :: tailC ->
yield! calculateOpenAny headA headC
yield! calculate c l tailA tailC
}
我有以下警告:
Fsc:C:\ myfile.fs(17,27):警告FS0025:此表达式上的模式匹配不完整。例如,值'(_,[_])'可能表示模式未涵盖的情况。
我不太了解,因为它不应该因为第一个条件语句而发生:
if arrayA.Length<>arrayC.Length then
这里是否有我想念的东西,还是可以忽略该警告?
答案 0 :(得分:3)
问题在于编译器不是万能的。它可以证明一些事物,但是它无法像人类一样完全分析您的程序,并注意语义。
尤其是,编译器不知道属性.Length
的值与列表形状之间的关系(即它是否为空)。从编译器的角度来看,Length
只是一个随机属性,您可能还比较了.ToString()
调用的结果。
一种更好的解决方法是在模式匹配中包含不同长度的大小写:
let rec calculate : Calculation<MyType> -> MyVO -> Calculation<MyType list>=
fun c l ->
fun arrayA arrayC ->
myComputationExpression {
match arrayA, arrayC with
| [], [] -> yield! C
| [a], [c] -> yield! calculate a c
| headA :: tailA, headC :: tailC ->
yield! calculateOpenAny headA headC
yield! calculate c l tailA tailC
| _, _ -> yield! l
}
这里的另一个好处是性能:计算列表的长度实际上是O(n)操作,因此最好避免使用它。
请注意,所有这些都是等效的:
fun a -> fun b -> fun c -> ...
fun a -> fun b c -> ...
fun a b -> fun c -> ...
fun a b c -> ...
这是因为参数在F#(以及所有ML系列)中是如何工作的:函数“一个一个”地获取参数,而不是一次全部获取,在每一步返回“期望”其余参数的另一个函数。这称为“ currying”。 F#中的函数默认为咖喱。
在您的情况下,这意味着您的函数可以这样声明得更短:
let rec calculate =
fun c l arrayA arrayC ->
...
或更短:
let rec calculate c l arrayA arrayC =
...