【问题标题】:How to detect commutative patterns in Ocaml using pattern matching?如何使用模式匹配检测 Ocaml 中的交换模式?
【发布时间】:2011-05-09 15:07:08
【问题描述】:

我需要在我的一个函数中检测交换模式。我认为编写以下内容可以完成工作:

let my_fun a b = match a,b with
  (*...*)
  | a,b
  | b,a when is_valid b -> process b  (***)
  (*...*)

这不起作用,Ocaml 抱怨 此子模式未使用 对标有(***) 的行发出警告。

1) 有人可以向我解释这个警告试图表达什么以及为什么这不起作用吗?

2) 考虑到我现在想知道哪个参数is_valid,我如何才能在不使用if then else 的情况下优雅地写这个?

2) 是否有可能只使用模式匹配而不重复 when is_valid b -> process b 来获得预期的功能,就像下面发生的那样?

let my_fun a b = match a,b with
  (*...*)
  | a,b when is_valid b -> process b
  | b,a when is_valid b -> process b 
  (*...*)

编辑:

在我的具体示例中,ab 是成对的。该函数有点复杂,但下面将说明情况:

let f a b = match a,b with
  | (a1,a2),(b1,b2)
  | (b1,b2),(a1,a2) when b1 = b2 -> a1 + a2

调用f (1,1) (1,2) 将导致模式匹配失败。我知道为什么(感谢下面的答案),并且我知道如果每个元素都有不同的构造函数(如 Ashish Agarwal 的回答),我如何使它工作。你能建议一种方法让它适用于我的情况吗?

【问题讨论】:

    标签: warnings pattern-matching ocaml


    【解决方案1】:

    匹配的工作方式是首先匹配模式,如果成功,然后通过该模式匹配中的附加环境评估条件。由于a,b 将始终绑定,因此这是唯一使用的情况,并且编译器正确报告b,a 从未使用过。你必须重复那行,

    let my_fun a b = match a,b with
      | a,b when is_valid b -> process b
      | b,a when is_valid b -> process b
    

    如果您没有对变量执行匹配,而是对某些变体执行匹配,则您的方法可能会起作用,例如,

    let my_fun a b = match a,b with
      | a, `Int b
      | `Int b, a when is_valid b -> process b
    

    编辑:考虑使用一个守卫作为子表达式的多个模式,

    let my_fun a b = match a,b with
      | ((a,b) | (b,a)) when is_valid b -> process b
    

    您将在patterns 的定义中看到这一点。它实际上是一个模式,由模式组成,被匹配。

    【讨论】:

    • 顺便说一下,不是“RTFM”,但如果您有兴趣,这里是此信息的来源,caml.inria.fr/pub/docs/manual-ocaml/expr.html
    • 根据您在找到匹配项后还指出的文档,评估条件。如果条件为假,则恢复匹配。这意味着在我的示例中匹配 a,b 后它应该测试 is_valid b。所以 a,b 不应该总是绑定。你能帮我理解我在这里缺少什么吗?
    • 我知道重复这一行会起作用,但这就是我试图避免的原因(后面的不仅仅是一行)。变体解决方案也对我不起作用。我基本上得到了相同的东西,但没有警告。
    • 我提到了变体来展示你可以在多场比赛中使用守卫,而不是作为一个可行的“解决方案”。当我们只知道两行代码时,很难提出建议。但是如果它长于一行,您总是可以在匹配上方创建一个函数,并将其称为一行。
    • 感谢您的更新。现在很清楚为什么事情会如此运作。至于一个具体的例子,我不知道它是否会增加更多价值。根据我目前的理解和您的回答,在这种情况下无法摆脱代码重复。如果我错了,请纠正我。无论如何,我更新了问题以反映这一点。
    【解决方案2】:

    对于您的第一个问题,要意识到您只有一个模式((a,b) | (b,a)),它恰好是一个“或”模式。匹配以“或”模式从左到右进行。由于(a,b) 将匹配任何内容,因此永远不会使用第二部分。

    关于你的第二个问题,我看不出问题,但这取决于ab 的类型。这是一个例子:

    type t = A of int | B of float
    
    let my_fun a b = match a,b with
      | A a, B b
      | B b, A a when b > 0. ->  (float_of_int a) +. b
      | … -> (* other cases *)
    

    它也适用于更简单的类型:

    let my_fun a b = match a,b with
      | 1,b
      | b,1 when b > 0 -> b + 1
      | … -> (* other cases *)
    

    如果您仍然无法在您的情况下使用此功能,请告诉我们您正在使用的 ab 的类型。

    【讨论】:

    • 谢谢。现在我明白了,如果我有不同的构造函数,我该如何让它工作。不过,我不能让它在我的情况下工作。我用一个具体的例子更新了这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 2011-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-31
    • 1970-01-01
    相关资源
    最近更新 更多