当两个模式共享一个"when"子句时,模式匹配不完整 [英] Incomplete pattern match when two patterns share a `when` clause

查看:110
本文介绍了当两个模式共享一个"when"子句时,模式匹配不完整的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于刚开始使用F#的程序员来说,常见的惊喜是以下内容不完全匹配的事实:

A common surprise for beginning F# programmers is the fact that the following is an incomplete match:

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

但是我刚遇到使我感到惊讶的情况.以下是一些示例代码来演示它:

But I just encountered a situation that surprised me. Here's a small bit of sample code to demonstrate it:

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表达式的匹配的特定分支,可以看出该模式匹配不会匹配任何可能的树:

This version of the describe function produced the "Incomplete pattern matches on this expression" warning, even though the pattern match is, in fact, complete. There are no possible trees that will not be matched by that pattern match, as can be seen by removing the specific branch of the match that had a when expression in it:

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树的普通树"字符串.

This version of describe returns the "Normal tree" string for both the sapling and twoLeafTree trees.

match表达式仅包含when表达式的情况下(如比较xy的第一个示例),F#编译器可能无法判断是合理的比赛是否完成.毕竟,xy 可能是具有比较和相等性的怪异"实现的类型,而这三个分支都不是真的.*

In the case where the match expression contains nothing but when expressions (like the first example where x and y are being compared), it is reasonable that the F# compiler might not be able to tell whether the match will be complete. After all, x and y might be types with a "weird" implementation of comparison and equality where none of those three branches are true.*

但是在类似我的describe函数的情况下,为什么F#编译器不查看该模式,说如果所有when表达式的求值为false,仍然会有完全匹配项",然后跳过不完整的模式匹配"警告?出现此警告是否有某些特定的原因,或者仅仅是F#编译器在这里有点简单化并由于其代码不够复杂而给出错误肯定警告的情况?

But in cases like my describe function, why doesn't the F# compiler look at the pattern, say "If all the when expressions evaluated to false, there would still be a complete match" and skip the "incomplete pattern matches" warning? Is there some specific reason for this warning showing up here, or is it just a case of the F# compiler being just a little bit simplistic here and giving a false-positive warning because its code wasn't sophisticated enough?

*实际上,可以将xy设置为x < yx = yx > y all 的值,而无需走出屋外标准.Net类型系统的正常"范围.作为特殊的奖励问题/难题,xy的这些值是多少?无需自定义类型即可解决这个难题;您需要的只是标准.Net中提供的类型.

* In fact, it is possible to set x and y to values such that x < y, x = y, and x > y are all false, without ever stepping outside the "normal" bounds of the standard .Net type system. As a special bonus question/puzzle, what are these values of x and y? No custom types needed to answer this puzzle; all you need is types provided in standard .Net.

推荐答案

在F#match语法中,when防护适用于之前列举的所有 all 情况,而不仅仅是最后一种情况一个.

In F# match syntax, the when guards apply to all cases enumerated just before it, not just to the last one.

在您的特定情况下,保护when saplingsGetSpecialTreatment适用于Leaf nBranch [Leaf n]情况.因此,当tree = Leaf 42 && saplingsGetSpecialTreatment = false

In your specific scenario, the guard when saplingsGetSpecialTreatment applies to both Leaf n and Branch [Leaf n] cases. So this match will fail for the case when tree = Leaf 42 && saplingsGetSpecialTreatment = false

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

The following would be complete, since the Leaf case now has its own branch:

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

这篇关于当两个模式共享一个"when"子句时,模式匹配不完整的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆