Können Sie nisten eine „doppelte cons“ Muster überein?
-
05-07-2019 - |
Frage
Ich mag ein Muster stärken nur Zahlen übereinstimmen, die eine zusätzliche Validierungsfunktion übergeben.
let (|IsValid|_|) n = ...
let (|Nil|One|Two|) (l : int list) =
match l with
| a :: b :: t -> Two(a + b)
| a :: t -> One(a)
| _ -> Nil
Der 'One' Fall ist einfach:
| IsValid(a) :: t -> One(a)
Der ‚Two‘ Fall ist mir nicht klar. Es braucht die Summe der Zahlen zu bestätigen. Kann ich dies tun, ohne einen, wenn Wache mit?
...
Edit: Ich habe eine, wenn Wache (mit einem Bool-Rückkehr isValid Funktion) wie folgt verwenden können:
| a :: b :: t when isValid a + b -> Two(a + b)
Dies ist weniger elegant als nur mit einem Muster übereinstimmen; Schlimmer noch, a + b angewandt zweimal.
Beachten Sie auch diese eine vereinfachte Version meiner eigentlichen Code ist (Ich versuche, nicht nur beispielsweise gegen unterschiedliche Längen der Liste übereinstimmen) - die Frage ist über verschachtelte Anpassung über das Doppel cons Muster.
Lösung
Meine Lösung: ein „Helfer“ Erkenner mit einem Rückgabewert hinzufügen entworfen, um in dem übergeordneten Muster verwendet werden:
let (|MatchTwo|_|) = function
| a :: b :: t -> Some(a + b :: t)
| _ -> None
Verwenden Sie es wie folgt:
let (|Nil|One|Two|) (l : int list) =
match l with
| MatchTwo(IsValid(a) :: t) -> Two(a)
| IsValid(a) :: t -> One(a)
| _ -> Nil
Andere Tipps
Wenn Sie das tun:
| a :: b :: t -> ...
Sie sind nicht unbedingt passend zwei Elemente in einer Liste. Es ist besser, []
statt t
zu verwenden, um zwei Elemente passen genau kann --t
eine Liste mit mehreren Elementen sein.
| a :: b :: [] -> Two (a+b)
Dadurch wird sichergestellt, dass Sie zwei passen und nur zwei Elemente --error kostenlos Kontrolle! Ich schlage vor, dies zu tun, auch wenn Sie die Funktion erwarten eine Liste von 0, 1 oder 2 Elementen nur zu akzeptieren. Also,
EDIT:
let (|MatchTwo|_|) = function
| a :: b :: t -> Some(a + b :: t)
| _ -> None
let (|Nil|One|Two|) (l : int list) = match l with
| MatchTwo(IsValid(a) :: t) -> Two(a)
| IsValid(a) :: t -> One(a)
| _ -> Nil
Ja, verwenden when
. Das ist ein Chaos. Pattern-Matching ist nur, dass die Anwendung Funktionen innerhalb des Spiels nicht wirklich Sinn machen. Aber berücksichtigen, was ich vor erwähnt habe. Basierend auf Ihrem Beispiel:
match l with
| a :: b :: t when isValid (a+b) -> Two (a+b)
| a :: t when isValid (a) -> One a
| _ -> Nil
Das zweite Muster wird Listen der Länge paßt länger dann ein, wenn isValid auf dem ersten Muster falsch ist --Seien gewarnt. Seien Sie so genau in Ihrem Muster wie möglich, wenn Sie bedeuten ein Element passen, es zu tun.
Wenn was auch immer Betrieb, den Sie verwenden, a und b zu kombinieren (in diesem Fall +) ist rechnerisch teuer, dann werden Sie die when
fallen lassen und eine let-Anweisung verwenden, bevor Sie die isValid Prüfung und Rückgabe des Variant-Typ.