使用不完整模式匹配作为过滤器

时间:2011-04-11 22:10:50

标签: f# pattern-matching list-comprehension

假设我有以下代码:

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

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

我可以使用不完整的模式匹配来过滤上面的列表,例如:

> 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.

由于忽略了无与伦比的元素是我的意图,是否有可能摆脱这种警告?

有没有办法让list-comprehensions使用而不会导致MatchFailureException?例如类似的东西:

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

3 个答案:

答案 0 :(得分:10)

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

代码的标准替代品是:

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

答案 1 :(得分:5)

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

但更一般地说,不,最好的事情是明确过滤,就像在另一个答案中一样(例如使用choose)。

答案 2 :(得分:5)

要明确声明您要忽略不匹配的案例,您可以使用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