当两个模式共享一个`''子句时,不完整的图案匹配



开始F#程序员的常见惊喜是以下事实是一个不完整的匹配:

let x, y = 5, 10
match something with
| _ when x < y -> "Less than"
| _ when x = y -> "Equal"
| _ when x > y -> "Greater than"

,但我只是遇到了使我感到惊讶的情况。这是一小部分示例代码来证明它:

type Tree =
| Leaf of int
| Branch of Tree list
let sapling = Branch [Leaf 1]  // Small tree with one leaf
let twoLeafTree = Branch [Leaf 1; Leaf 2]
let describe saplingsGetSpecialTreatment tree =
    match tree with
    | Leaf n
    | Branch [Leaf n] when saplingsGetSpecialTreatment ->
        sprintf "Either a leaf or a sapling containing %d" n
    | Branch subTree ->
        sprintf "Normal tree with sub-tree %A" subTree
describe true sapling // Result: "Either a leaf or a sapling containing 1"
describe false sapling // Result: "Normal tree with sub-tree [Leaf 1]"
describe true twoLeafTree // Result: "Normal tree with sub-tree [Leaf 1; Leaf 2]"
describe false twoLeafTree // Result: "Normal tree with sub-tree [Leaf 1; Leaf 2]"

此版本的describe函数产生了"此表达式上的不完整模式匹配"警告,即使模式匹配实际上是完整的。没有可能的树不会与该模式匹配匹配,正如删除 的特定分支所看到的,其中包含when表达式:

let describe tree =
    match tree with
    | Leaf n -> sprintf "Leaf containing %d" n
    | Branch subTree ->
        sprintf "Normal tree with sub-tree %A" subTree

此版本的describe返回saplingtwoLeafTree树的"正常树"字符串。

match表达式除了when表达式之外什么都没有的情况(例如,比较xy的第一个示例(,合理的F#编译器可能无法分辨匹配项是否完成。毕竟,xy 可能是类型的类型,具有"怪异"的比较和平等实现,而这三个分支都不是True。*

但是,在我的describe函数等情况下,为什么F#编译器不看模式,请说"如果所有when表达式评估到false,仍然会有完整的匹配项",然后跳过"不完整的模式匹配"警告?是否有一些特定原因在这里显示此警告,还是仅仅是F#编译器在这里有点简单并给出虚假阳性的警告,因为它的代码不够复杂?

*实际上,可以将xy设置为值,例如x < yx = yx > y em> ALL all false,而无需超出标准.NET的"正常"边界类型系统。作为一个特殊的奖励问题/难题,这些xy的值是什么?无需自定义类型来回答这个难题;您需要的只是标准.NET中提供的类型。

在f# match语法中, when警卫适用于所有案例,而不仅仅是最后一个。

在您的特定情况下,后卫when saplingsGetSpecialTreatment适用于Leaf nBranch [Leaf n]案例。因此,当tree = Leaf 42 && saplingsGetSpecialTreatment = false

的情况下,这场比赛将失败

以下内容将完成,因为Leaf情况现在有其自己的分支:

let describe saplingsGetSpecialTreatment tree =
    match tree with
    | Leaf n ->
        sprintf "Either a leaf or a sapling containing %d" n
    | Branch [Leaf n] when saplingsGetSpecialTreatment ->
        sprintf "Either a leaf or a sapling containing %d" n
    | Branch subTree ->
        sprintf "Normal tree with sub-tree %A" subTree

只需用一个额外的示例澄清Fyodor的帖子即可。将其视为y = 3部分时,否则为部分,然后是其他所有内容

let f y x = 
  match x with
  | 0 
  | 1 
  | 2 when y = 3 -> "a"
  | 0
  | 1
  | 2            -> "b"
  | _            -> "c"
[0 .. 3] |> List.map (f 3)
[0 .. 3] |> List.map (f 2)

fsi

val f : y:int -> x:int -> string
> val it : string list = ["a"; "a"; "a"; "c"]
> val it : string list = ["b"; "b"; "b"; "c"]

那么,这是明智的默认值吗?我想是这样。

这是一个更明确的版本:

let f2 y x =
  match x,y with
  | 0,3
  | 0,3
  | 0,3 -> "a"
  | 0,_
  | 1,_
  | 2,_ -> "b"
  | _ -> "c"
[0 .. 3] |> List.map (f2 3)
[0 .. 3] |> List.map (f2 2)

...和一个更紧凑的版本:

let f3 y x = x |> function | 0 | 1 | 2 when y = 3 -> "a"
                           | 0 | 1 | 2 -> "b"
                           | _ -> "c"

相关内容

  • 没有找到相关文章

最新更新