Использование неполного сопоставления с образцом в качестве фильтра?
Предположим, у меня есть следующий код:
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.
Поскольку мое намерение заключается в игнорировании непревзойденных элементов, есть ли возможность избавиться от этого предупреждения?
И есть ли способ заставить эту работу работать со списками, не вызывая исключение MatchFailureException? например что-то подобное:
> [for Car(_, seats) in xs -> seats] |> List.sum;;
val it : int = 10
3 ответа
Два года назад ваш код был действительным, и это был стандартный способ сделать это. Затем язык был очищен, и проектное решение было в пользу явного синтаксиса. По этой причине я думаю, что не стоит игнорировать предупреждение.
Стандартная замена для вашего кода:
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
Вы можете отключить любое предупреждение через #nowarn
директива или --nowarn:
опция компилятора (передайте номер предупреждения, здесь 25
как в FS0025
).
Но в целом нет, лучше всего явно фильтровать, как в другом ответе (например, с choose
).
Чтобы явно указать, что вы хотите игнорировать несопоставленные случаи, вы можете использовать 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