Использование неполного сопоставления с образцом в качестве фильтра?

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

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

person Alexander Battisti    schedule 11.04.2011    source источник
comment
Я думаю, что эта строка должна была быть: [для Bus(_, мест) в xs -> мест] |› List.sum;; Верно? ;)   -  person    schedule 12.04.2011
comment
Я понял!!! 2 машины! 5 х 2 = 10! Господи, помоги мне.   -  person    schedule 12.04.2011
comment
Это семейный и спортивный автомобиль, поэтому 8 + 2 = 10.   -  person Laurent    schedule 12.04.2011


Ответы (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
person Laurent    schedule 11.04.2011
comment
Интересно. У вас есть ссылка / ссылка, описывающая упомянутую вами очистку, и обсуждайте обоснование этого изменения? - person gasche; 12.04.2011
comment
@gasche: у меня на компьютере старые компиляторы, могу сказать, что изменения произошли между версиями 1.9.3.14 и 1.9.6.16. Я не могу найти подходящую ссылку для этого, но в примечаниях к выпуску упоминается упрощение синтаксиса: ссылка. Здесь также есть обсуждение: ссылка. - person Laurent; 12.04.2011
comment
Поскольку паттерны могут быть сложными (или определяться как активные паттерны), читателю не всегда было ясно, является ли цикл фильтрующим или нет. Я предполагаю, что это может быть оправданием (лично мне понравился этот синтаксис). Кроме того, когда вы видите, как циклы for в вычислительных выражениях обесцениваются, становится ясно, что возникает исключение MatchFailureException. - person Laurent; 12.04.2011

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

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

person Brian    schedule 11.04.2011
comment
Я надеялся, что есть возможность отключить это предупреждение локально, например. с помощью атрибута. Но все равно спасибо! :) - person Alexander Battisti; 12.04.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
person pad    schedule 11.04.2011
comment
Вы можете сделать это более кратким, например xs |> List.choose (function Car(kind,_) -> Some(kind) | _ -> None) - person Stephen Swensen; 12.04.2011
comment
Спасибо. ваш ответ также был очень полезен (и трудно выбрать между вашим и Лораном). - person Alexander Battisti; 12.04.2011