2011-04-11 14 views
5

Załóżmy, że mają następujące oznaczenia:Używanie niekompletnego dopasowywania wzorca jako filtra?

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

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

można filtrować powyżej listy za niepełny dopasowanie wzorca w imperatywem pętli jak:

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

found family 
found sports 
val it : unit =() 

ale spowoduje to: 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.

Jako że ignorowanie niedopasowanych elementów jest moją intencją, czy istnieje możliwość pozbycia się tego ostrzeżenia?

Czy istnieje sposób, aby to działało ze zrozumieniem listy bez powodowania wyjątku MatchFailureException? na przykład coś takiego:

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

Myślę, że linia miała wyglądać następująco: [dla Bus (_, miejsc) w xs -> miejsc] |> List.sum ;; Dobrze? ;) –

+0

Och, rozumiem! 2 samochody! 5 x 2 = 10! Panie, pomóż mi. –

+0

To samochód rodzinny i samochód sportowy, więc 8 + 2 = 10. – Laurent

Odpowiedz

10

Dwa lata temu Twój kod był ważny i był to standardowy sposób. Następnie język został oczyszczony, a decyzja projektowa miała sprzyjać wyraźnej składni. Z tego powodu uważam, że ignorowanie ostrzeżenia nie jest dobrym pomysłem.

Standardowy zamiennik kodzie jest:

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

(można też użyć funkcji wysokiej zamówienie w próbce PAD)

Dla drugiego, List.sumBy będzie dobrze pasować:

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

Jeśli wolisz trzymać listowe, jest to wyraźny składnia:

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

Interesujące. Czy posiadasz odnośnik/link opisujący "sprzątający", o którym wspomniałeś, i omawiasz uzasadnienie tej zmiany? – gasche

+4

@gasche: Mam stare kompilatory na moim komputerze, mogę powiedzieć, że nastąpiła zmiana między wersjami 1.9.3.14 i 1.9.6.16. Nie mogę znaleźć odpowiedniego odniesienia do tego, ale te informacje o wydaniu wspominają o uproszczeniu składni: [link] (http: //blogs.msdn.com/b/dsyme/archive/2008/08/29/detailed-release-notes-for-the-f-september-2008-ctp-release.aspx). Istnieje również dyskusja tutaj: [link] (http://cs.hubfs.net/forums/thread/12072.aspx). – Laurent

+1

Ponieważ wzorce mogą być złożone (lub zdefiniowane jako aktywne wzorce), nie zawsze było jasne dla czytelnika, czy pętla filtrowała, czy nie. Myślę, że to może być uzasadnienie (osobiście, podobała mi się ta składnia). Ponadto, gdy zobaczysz, jak pętle w wyrażeniach obliczeniowych są pomijane, jest jasne, że zwiększa się wyjątek MatchFailureException. – Laurent

5

Można wyciszyć żadnego ostrzeżenia poprzez dyrektywa #nowarn lub --nowarn: opcja kompilatora (przesuń liczbę ostrzegawczy, tutaj 25 jak w FS0025).

Ale bardziej ogólnie, nie, najlepszą rzeczą jest jawne filtrowanie, tak jak w przypadku drugiej odpowiedzi (np. Z choose).

+1

Mam nadzieję, że istnieje możliwość wyłączenia tego ostrzeżenia na miejscu, np. za pomocą atrybutu. Ale mimo to dziękuję! :) –

5

Aby wyraźnie stwierdzić, że chcesz ignorować niedopasowane sprawy, możesz użyć List.choose i zwrócić None dla tych niedopasowanych elementów. Twoje kody mogą być napisane w bardziej idomatyczny sposób:

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

Możesz uczynić to bardziej zwięzłym jak 'xs |> List.choose (funkcja Car (rodzaj, _) -> Some (rodzaj) | _ -> None)' –

+0

dziękuję. twoja odpowiedź była również bardzo pomocna (i trudna do rozstrzygnięcia między twoją a Laurenta). –

Powiązane problemy