Использование неполного сопоставления с образцом в качестве фильтра? - PullRequest
5 голосов
/ 12 апреля 2011

Предположим, у меня есть следующий код:

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

Ответы [ 3 ]

10 голосов
/ 12 апреля 2011

Два года назад ваш код был действительным, и это был стандартный способ сделать это.Затем язык был очищен, и проектное решение было в пользу явного синтаксиса.По этой причине я думаю, что не стоит игнорировать предупреждение.

Стандартная замена для вашего кода:

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

(вы также можете использовать функции высокого порядка вобразец сэмпла)

Для другого List.sumBy вполне подойдет:

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

Если вы предпочитаете придерживаться понимания, это явный синтаксис:

[for x in xs do
    match x with
    | Car(_, seats) -> yield seats
    | _ -> ()
] |> List.sum
5 голосов
/ 12 апреля 2011

Чтобы явно указать, что вы хотите игнорировать несопоставленные случаи, вы можете использовать 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
5 голосов
/ 12 апреля 2011

Вы можете отключить любое предупреждение с помощью директивы #nowarn или опции компилятора --nowarn: (передайте номер предупреждения, здесь 25, как в FS0025).

Но в более общем случае, нет,Лучше всего явно фильтровать, как в другом ответе (например, с choose).

...