【问题标题】:Using incomplete pattern matching as filter?使用不完整的模式匹配作为过滤器?
【发布时间】:2011-04-11 22:10:49
【问题描述】:

假设我有以下代码:

type Vehicle =
| Car  of string * int
| Bike of string

let xs = [ Car("family", 8); Bike("racing"); Car("sports", 2); Bike("chopper") ]

我可以在命令式 for 循环中使用不完整的模式匹配过滤上面的列表,例如:

> for Car(kind, _) in xs do
>    printfn "found %s" kind;;

found family
found sports
val it : unit = ()

但会导致:warning FS0025: Incomplete pattern matches on this expression. For example, the value 'Bike (_)' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored.

由于我的意图是忽略不匹配的元素,有没有可能摆脱这个警告?

有没有一种方法可以在不导致 MatchFailureException 的情况下使用列表理解?例如类似的东西:

> [for Car(_, seats) in xs -> seats] |> List.sum;;
val it : int = 10

【问题讨论】:

  • 我认为该行应该是:[for Bus(_, seat) in xs -> seat] |> List.sum;;对? ;)
  • 哦,我明白了! 2车! 5 x 2 = 10!主啊,帮助我。
  • 这是一辆家用车和一辆跑车,所以 8 + 2 = 10。

标签: f# pattern-matching list-comprehension


【解决方案1】:

两年前,您的代码是有效的,并且是执行此操作的标准方式。然后,语言已被清理,设计决定是支持显式语法。因此,我认为忽略该警告并不是一个好主意。

您的代码的标准替换是:

for x in xs do
    match x with
    | Car(kind, _) -> printfn "found %s" kind
    | _ -> ()

(您也可以使用 pad 示例中的高阶函数)

对于另一个,List.sumBy 很合适:

xs |> List.sumBy (function Car(_, seats) -> seats | _ -> 0)

如果您更喜欢使用推导式,这是显式语法:

[for x in xs do
    match x with
    | Car(_, seats) -> yield seats
    | _ -> ()
] |> List.sum

【讨论】:

  • 有趣。您是否有描述您提到的“清理”的参考/链接,并讨论此更改的理由?
  • @gasche:我的电脑上有旧的编译器,我可以告诉你版本 1.9.3.14 和 1.9.6.16 之间发生的变化。我找不到合适的参考资料,但那些发行说明提到了语法简化:link。这里也有讨论:link.
  • 由于模式可能很复杂(或定义为活动模式),读者并不总是清楚循环是否在过滤。我想这可能是一个理由(就我个人而言,我喜欢这种语法)。此外,当您看到计算表达式中的 for 循环如何被脱糖时,很明显它引发了 MatchFailureException。
【解决方案2】:

您可以通过#nowarn 指令或--nowarn: 编译器选项使任何警告静音(传递警告编号,此处为25,如FS0025)。

但更一般地说,不,最好的办法是显式过滤,就像在另一个答案中一样(例如使用choose)。

【讨论】:

  • 我希望有可能在本地禁用此警告,例如通过使用属性。不过还是谢谢! :)
【解决方案3】:

要明确声明要忽略不匹配的情况,可以使用List.choose 并为那些不匹配的元素返回None。您的代码可以以更惯用的方式编写如下:

let _ = xs |> List.choose (function | Car(kind, _) -> Some kind
                                    | _ -> None)
           |> List.iter (printfn "found %s")

let sum = xs |> List.choose (function | Car(_, seats)-> Some seats
                                      | _ -> None) 
             |> List.sum

【讨论】:

  • 你可以让这个更简洁,比如xs |> List.choose (function Car(kind,_) -> Some(kind) | _ -> None)
  • 谢谢。你的回答也很有帮助(很难在你和 Laurent 之间做出决定)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-28
  • 1970-01-01
  • 2011-08-24
  • 2016-10-02
  • 2013-09-12
相关资源
最近更新 更多