【问题标题】:Negative pattern match负模式匹配
【发布时间】:2017-10-09 09:40:36
【问题描述】:

我有以下代码(`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",但该特定示例无法编译。我知道守卫,但这似乎并不比原来的解决方案干净。

是否可以在不使用守卫的情况下进行“负”(逻辑非)模式匹配,即一个值不应该与其他值匹配?

【问题讨论】:

  • 你可以添加一个守卫:{Field1 = f} when f <> "invalid".
  • 谢谢。我知道警卫,并打算在问题中提及这一点。现已更新。

标签: f# pattern-matching


【解决方案1】:

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

【讨论】:

    【解决方案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
    ...
    

    【讨论】:

    • 谢谢。我实际上在发布之前尝试过,正如你所说,它不适用于子模式。不幸的是,在我的情况下需要子模式,但我不认为将其包含在问题中。我现在更新了问题以澄清这一点。
    • @cmeeren 好吧,您可以有另一个活动模式:let (|ToLower|) x = (x:string).ToLower(),然后执行ToLower (Not "invalid"),但现在它变得很愚蠢......我认为您在模式匹配方面做得太多了。使用警卫或一种专门的活动模式:)
    【解决方案3】:

    我会使用这样的主动模式

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-03
      • 1970-01-01
      相关资源
      最近更新 更多