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.

War es hilfreich?

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top