6

考虑以下无意义的 lambda:

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

这工作正常。现在我重写如下:

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

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

警告 FS0025:此表达式的模式匹配不完整。例如,值“[]”可能表示模式未涵盖的情况。

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

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

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

4

2 回答 2

6

我认为 F# 编译器在这种情况下是实用的。

最后,第二条规则可以表示为对输入列表的约束xs

xs = hd :: tl && xs = l

F# 编译器似乎没有探索&&约束。这是合理的,因为约束可以任意复杂并且&很少使用。

我们对部分活动模式也有类似的问题:

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"

于 2013-08-23T06:57:36.210 回答
4

我猜你发现了另一种情况(除了when子句和部分活动模式)编译器的决策过程不够强大。(这就是为什么警告消息说可能表明:-))。

如果您想在没有警告的情况下获得相同的功能,那么您可以使用这样的完整活动模式(但实际上,对于列表,我可能只会使用_@pad 建议的空列表案例):

let (|Empty|NonEmpty|) l =
  match l with [] -> Empty | x::xs -> NonEmpty(x, xs, l)

let foo = function  
  | Empty -> 0
  | NonEmpty(x, xs, l) -> 1
于 2013-08-23T12:08:44.477 回答