F#模式匹配奇怪

luk*_*san 6 f# pattern-matching

考虑以下废话lambda:

function
| [] -> "Empty list"
| hd::tl -> "Not so empty list"
Run Code Online (Sandbox Code Playgroud)

这很好用.现在我重写如下:

function
| [] -> "Empty list"
| hd::tl & l -> "Not so empty list"
Run Code Online (Sandbox Code Playgroud)

同样,出于无意义的原因(并且我知道我可以通过使用as代替而实现相同的效果&,但这都与代码 - 高尔夫问题有关,这与此问题无关).现在F#编译器告诉我:

警告FS0025:此表达式上的不完整模式匹配.例如,值"[]"可以指示模式未涵盖的情况.

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

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

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

pad*_*pad 6

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

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

xs = hd :: tl && xs = l
Run Code Online (Sandbox Code Playgroud)

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

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

let (|Empty|_|) = function
    | [] -> Some()
    | _ -> None

let (|NonEmpty|_|) = function
    | _ :: _ -> Some()
    | _ -> None

// warning FS0025
let f = function
    | Empty -> "Empty list"
    | NonEmpty -> "Not so empty list"
Run Code Online (Sandbox Code Playgroud)

要解决此问题,您可以:

  • 使用as而不是&,这更合适,因为l它只是一个绑定.
  • 在末尾添加通配符模式以消除警告.我经常写

    let f =
        function
        | hd::tl & l -> "Not so empty list"
        | _ -> "Empty list"
    
    Run Code Online (Sandbox Code Playgroud)
  • 使用禁止警告nowarn "25".