模式匹配警告

时间:2020-05-14 14:36:13

标签: f#

我正在如下功能中使用模式匹配:

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 

这里是否有我想念的东西,还是可以忽略该警告?

1 个答案:

答案 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 =
   ...