2013-08-23 2 views
6

Betrachten Sie die folgende Unsinn Lambda:F # Musterabgleich Kuriosität

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

Dies funktioniert gut. Jetzt habe ich es wie folgt umschreiben:

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

Auch für Unsinn Gründen (und ich weiß, dass ich durch die Verwendung as statt & die gleiche Wirkung erzielen können, aber dies alles mit einem Code-Golf-Problem zu tun hat, das ist für diese Frage nicht relevant). Jetzt der F # Compiler sagt mir:

Warnung FS0025: Unvollständige Muster passt auf diesen Ausdruck. Für Beispiel kann der Wert '[]' einen Fall anzeigen, der nicht durch die Muster abgedeckt ist.

Das ergibt keinen Sinn - ich behandle ausdrücklich den Fall [] in der ersten Regel. Ich sehe nicht, was sich von der ersten Funktion zur zweiten in Bezug auf [] geändert hat; Die zweite Regel von function hätte es nicht erreicht, aber nur die zweite Funktion gibt die Warnung aus. Alles, was ich tat, war ein zusätzliches Muster, das alles entspricht.

Natürlich ist der Aufruf der zweiten Funktion mit einer leeren Liste erfolgreich.

Gibt es einen triftigen Grund, warum diese Warnung aufgetreten ist, oder hat die F # Mustervalidierung einfach einige Macken? Ich könnte sehen, einige Fälle wie diese zu haben, wenn fortgeschrittenere Muster verwendet werden, aber das scheint wie ein ziemlich einfaches. Selbst wenn das Problem nicht allgemein gelöst werden kann, scheint es, als ob diese Art von Fall häufig genug wäre, um eine besondere Behandlung im Compiler zu verdienen.

+1

ich habe nie '' '' auf diese Weise gesehen. Kannst du mit einer Dokumentation darüber verlinken? – JaredPar

+3

@ JaredPar - siehe AND Muster hier http://msdn.microsoft.com/en-us/library/dd547125.aspx. Grundsätzlich bedeutet es, dass Sie Kopf, Schwanz und die gesamte Liste in einem Rutsch bekommen können –

Antwort

6

Ich denke F # Compiler ist in diesem Fall praktisch.

xs = hd :: tl && xs = l 

F # -Compiler nicht && Einschränkungen zu erkunden scheinen:

Am Ende kann die zweite Regel als xs auf Eingabeliste Einschränkung ausgedrückt werden. Dies ist vernünftig, da Constraints beliebig komplex sein können und die Verwendung von & ziemlich selten ist.

Wir haben ein ähnliches Problem mit 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" 

um dieses Problem zu beheben, können Sie:

  • Verwenden as statt &, die besser geeignet ist, da l nur eine Bindung ist.
  • Fügen Sie am Ende ein Platzhaltermuster hinzu, um die Warnung zu beseitigen. Ich schreibe in der Regel

    let f = 
        function 
        | hd::tl & l -> "Not so empty list" 
        | _ -> "Empty list" 
    
  • Unterdrückt die Warnung mit nowarn "25".

+0

Ja, ich habe die Warnung mit den teilweise aktiven Mustern zuvor gesehen. Das macht jedoch Sinn, da aktive Muster kompilierte Funktionen und keine Makros sind und daher der Compiler die Vollständigkeit der Übereinstimmungen nicht statisch überprüfen kann. Nun, wenn es eine Möglichkeit gäbe, ein aktives Muster mit dem Inline-Schlüsselwort zu definieren (ich habe es versucht), könnte das eine andere Geschichte sein. – luksan

+1

Sie können 'inline' mit aktiven Mustern verwenden:' let inline (| Empty | _ |) xs = passt xs mit [] -> Some() | an _ -> None', aber die Warnung ist immer noch da. – pad

+0

Ich denke du hast Recht. Wenn ich aber '<@@ function [] -> Some() | _ -> None @@> 'Ich sehe, dass der AST für den Übereinstimmungsausdruck nur ein If/Else ist, so dass die Musterinformationen immer noch verloren sind. – luksan

4

Ich denke, man einen anderen Fall gefunden (abgesehen von when Klauseln und teilweise aktiven Muster), wo die Entscheidungsprozedur des Compilers nicht stark genug ist. (Deshalb lautet die Warnmeldung möglicherweise :-)).

Wenn Sie die gleiche Funktionalität ohne Warnungen erhalten möchten, könnten Sie ein vollständiges aktives Muster wie dieses verwenden (aber in Wirklichkeit würde ich für Listen wahrscheinlich nur mit _ für den leeren Listenfall gehen, wie @pad vorschlägt) :

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

Es sagt "kann anzeigen", aber es sagt auch "unvollständig" eher "möglicherweise unvollständig", so dass es etwas mehrdeutig ist. – luksan