2013-08-23 19 views
6

Rozważmy następujący nonsense lambda:F # wzorzec dopasowania kuriozum

function 
| [] -> "Empty list" 
| hd::tl -> "Not so empty list" 

To działa prawidłowo. Teraz przepisać go w następujący sposób:

function 
| [] -> "Empty list" 
| hd::tl & l -> "Not so empty list" 

Ponownie, ze względów nonsensownych (i wiem, że mogę osiągnąć ten sam efekt przy użyciu as zamiast &, ale to wszystko ma do czynienia z problemem code-golf to nie dotyczy tego pytania). Teraz kompilator F # informuje mnie:

ostrzeżenie FS0025: Niepełny wzorzec pasujący do tego wyrażenia. Dla przykładu , wartość "[]" może wskazywać na przypadek nieobjęty wzorami (wzorami) .

To nie ma sensu - w pierwszej regule wyraźnie posługuję się sprawą []. Nie widzę, co zmieniło się z pierwszej funkcji na drugą w odniesieniu do []; żadna z drugich zasad nie pasowałaby do tego, ale tylko druga funkcja daje ostrzeżenie. Wszystko co zrobiłem, to dodać dodatkowy wzór, który pasuje do czegokolwiek, co jest.

Oczywiście wywołanie drugiej funkcji z pustą listą kończy się pomyślnie.

Czy istnieje ważny powód, dla którego to ostrzeżenie wystąpiło, lub czy sprawdzanie wzorca F # ma po prostu jakieś dziwactwa? Mogłem zauważyć, że niektóre przypadki są takie, gdy stosuje się bardziej zaawansowane wzorce, ale wydaje się to dość proste. Nawet jeśli problemu nie można rozwiązać w ogólności, wydaje się, że ten typ przypadku byłby na tyle powszechny, że zasługuje na specjalną obsługę w kompilatorze.

+1

Nigdy nie widziałem "i" używanych w ten sposób. Czy możesz połączyć się z dokumentacją na temat tego, co to robi? – JaredPar

+3

@JaredPar - zobacz I wzór tutaj http://msdn.microsoft.com/en-us/library/dd547125.aspx. Zasadniczo oznacza to, że możesz uzyskać głowę, ogon i całą listę za jednym razem –

Odpowiedz

6

Myślę, że kompilator F # jest praktyczny w tym przypadku.

W końcu druga reguła może być wyrażona jako ograniczenie na liście wejściowej xs:

xs = hd :: tl && xs = l 

F # kompilator nie wydaje się zbadać && ograniczeń. Jest to uzasadnione, ponieważ ograniczenia mogą być dowolnie złożone, a korzystanie z & jest dość rzadkie.

Mamy podobny problem z partial active patterns:

let (|Empty|_|) = function 
    | [] -> Some() 
    | _ -> None 

let (|NonEmpty|_|) = function 
    | _ :: _ -> Some() 
    | _ -> None 

// warning FS0025 
let f = function 
    | Empty -> "Empty list" 
    | NonEmpty -> "Not so empty list" 

Aby rozwiązać ten problem, można:

  • Zastosowanie as zamiast &, który jest bardziej odpowiedni od l tylko wiążące.
  • Dodaj wzór wieloznaczny do końca, aby wyeliminować ostrzeżenie. I zazwyczaj napisać

    let f = 
        function 
        | hd::tl & l -> "Not so empty list" 
        | _ -> "Empty list" 
    
  • tłumić ostrzegania za pomocą nowarn "25".

+0

Tak, widziałem wcześniej ostrzeżenie z częściowymi aktywnymi wzorami. To jednak ma sens, ponieważ aktywne wzorce są skompilowanymi funkcjami, a nie makrami, dlatego kompilator nie może statycznie zweryfikować kompletności dopasowań. Teraz, jeśli istnieje jakiś sposób zdefiniowania aktywnego wzoru za pomocą słowa kluczowego 'inline' (próbowałem), może to być inna historia. – luksan

+1

Możesz użyć 'inline' z aktywnymi wzorami:' let inline (| Empty | _ |) xs = mecz xs z [] -> Some() | _ -> None', ale ostrzeżenie nadal istnieje. – pad

+0

Chyba masz rację. Chociaż jeśli zrobię "<@@ function [] -> Some() | _ -> Brak @@> 'Rozumiem, że wyrażenie AST dla wyrażenia dopasowania jest po prostu if/else, więc informacja o wzorze jest nadal tracona. – luksan

4

Chyba znalazł inną sprawę (oprócz when klauzul i częściowych aktywnych wzorów), gdzie procedura decyzyjna kompilator nie jest wystarczająco silny. (Właśnie dlatego komunikat ostrzegawczy mówi: może oznaczać :-)).

Jeśli chcesz uzyskać tę samą funkcjonalność bez ostrzeżeń, możesz użyć pełnego aktywnego wzorca, takiego jak ten (ale w rzeczywistości, w przypadku list, prawdopodobnie skorzystałbym z _ dla pustej listy, jak sugeruje @pad) :

let (|Empty|NonEmpty|) l = 
    match l with [] -> Empty | x::xs -> NonEmpty(x, xs, l) 

let foo = function 
    | Empty -> 0 
    | NonEmpty(x, xs, l) -> 1 
+0

Mówi "może wskazywać", ale również mówi "niekompletny" raczej "prawdopodobnie niepełny", więc jest nieco niejednoznaczny. – luksan

Powiązane problemy