负模式匹配

时间:2017-10-09 09:40:37

标签: f# pattern-matching

我有以下代码(`IgnoreCase是我在别处定义的活动模式):

match myType with
| {Field1 = IgnoreCase "invalid"} -> None
| {Field2 = Some f2
   Field3 = Some f3
   Field4 = None | Some (0 | 1 | 2)}
    -> Some (f2, f3)
| _ -> None

正如您所看到的,Field1列入了黑名单,Field4列入了白名单(Field2Field3也必须Some }})。如果我可以在相同的情况下进行所有检查,即使Field1 = IgnoreCase "invalid"与其他匹配一起使用,例如使用例如恕我直言,它会看起来更清晰一些。 Field1 <> IgnoreCase "invalid",但该特定示例无法编译。我知道守卫,但这似乎并不比原来的解决方案更清晰。

在不使用警卫的情况下,某个值与其他值不匹配的意义上是否可以执行“否定”(逻辑NOT)模式匹配?

3 个答案:

答案 0 :(得分:3)

据我所知,没有好方法可以做到这一点。您可以看到支持的模式here,并验证没有否定的构造。缺少这种特征的一个原因可能是它会与其他模式匹配特征奇怪地相互作用(例如,在负上下文中引入具有as模式的标识符是什么意思?)。这不是你可以通过活动模式以一般方式实现的东西,因为活动模式接收值而不是模式表达式。

答案 1 :(得分:2)

您可以定义名为Not的活动模式:

let (|Not|_|) a b = if a <> b then Some () else None

然后你可以在模式匹配中使用它:

match myType with
| {Field1 = Not "invalid"
   Field2 = Some f2
   Field3 = Some f3
   Field4 = None | Some (0 | 1 | 2)}
   -> Some (f2, f3)
| _ -> None

此活动模式的限制是它必须采用文字值,而不是子模式。活动模式不像内置模式那样可组合。但是,这也是一个潜在的优势,因为您可以将标识符作为值传递,而不是将新值绑定到标识符:

let invalidString = "invalid"

match myType with
| {Field1 = Not invalidString
...

答案 2 :(得分:1)

我会使用像这样的活动模式

let (|Check|_|) x =
    let = { Field2 = f2; Field3 = f3; Field4 = f4 }
    let check = 
        f4 = None ||
        f4 = Some 1 ||
        f4 = Some 2 ||
        f4 = Some 3
    if check then Some (f2, f3) else None

    match myType with
    | {Field1 = "invalid"} -> None
    | Check (x, y) -> Some (x, y)
    | _ -> None