F#模式匹配奇怪

时间:2013-08-23 05:34:11

标签: f# pattern-matching

考虑以下无意义的lambda:

function
| [] -> "Empty list"
| hd::tl -> "Not so empty list"

这很好用。现在我按如下方式重写它:

function
| [] -> "Empty list"
| hd::tl & l -> "Not so empty list"

同样,出于无意义的原因(我知道我可以通过使用as代替&来达到相同的效果,但这一切都与代码高尔夫问题有关,而这与我们无关这个问题)。现在F#编译器告诉我:

  

警告FS0025:此表达式上的不完整模式匹配。对于   例如,值'[]'可能表示未涵盖的案例   图案(多个)。

这没有任何意义 - 我在第一条规则中明确处理[]的情况。关于[],我没有看到从第一个函数到第二个函数的变化;函数的第二个规则都不匹配它,但只有第二个函数给出警告。我所做的只是添加一个匹配任何的其他模式。

当然,使用空列表调用第二个函数确实成功。

是否有正确的理由发生此警告,或者F#模式验证是否只是有一些怪癖?当使用更高级的模式时,我可以看到有这样的情况,但这似乎是一个非常基本的模式。即使问题一般无法解决,似乎这种类型的情况也足够普遍,值得在编译器中进行特殊处理。

2 个答案:

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