2014-05-13 8 views
7

Hier ist mein Problem: Ich versuche, einen Parser zu schreiben, der die Kraft aktiver Muster in F # nutzt. Die grundlegende Signatur einer Parsing-Funktion ist die folgendeF #: Erweiterte Verwendung von aktiven Mustern

LazyList<Token> -> 'a * LazyList<Token> 

Bedeutung eine faul Liste von Token nimmt, und gibt das Ergebnis des Parsing und die neue Liste von Tokens nach dem Parsen, so wie funktionales Design zu folgen.

nun als nächsten Schritt kann ich aktive Muster definieren, die mir einige Konstrukte direkt in Übereinstimmung Ausdrücke passen helfen, thusly

let inline (|QualName|_|) token_stream = 
    match parse_qualified_name token_stream with 
     | Some id_list, new_stream -> Some (id_list, new_stream) 
     | None, new_stream -> None 

let inline (|Tok|_|) token_stream = 
    match token_stream with 
     | Cons (token, tail) -> Some(token.variant, tail) 
     | _ -> None 

und dann passen Ergebnisse analysieren in einem hohen Maß Art und Weise auf diese Weise

Das Problem, das ich mit diesem Code habe, ist, dass jedes neue übereinstimmende Konstrukt geschachtelt ist, was nicht lesbar ist, vor allem, wenn Sie eine lange Kette von Ergebnissen haben. Ich möchte die Möglichkeit haben, einen Anpassungsoperator wie der Operator :: für die Liste zu definieren, die es mir ermöglichen würde folgendes zu tun:

let parse_subprogram_profile = function 
    | Tok (Kw (KwProcedure | KwFunction)) :: 
     QualName(qual_name) :: 
     Tok (Punc (OpeningPar)) :: stream_tail as token_stream -> 
     // some code 
    | token_stream -> None, token_stream 

Aber ich glaube nicht, so etwas ist möglich F #. Ich würde sogar ein Design akzeptieren, bei dem ich ein spezifisches aktives "ChainN" -Muster aufrufen muss, wobei N die Nummer des Elementes ist, das ich analysieren möchte, aber ich weiß nicht, wie ich eine solche Funktion entwerfen soll, wenn es möglich ist.

Irgendwelche Ratschläge oder Anweisungen diesbezüglich? Gibt es ein offensichtliches Design, das ich nicht gesehen habe?

Antwort

3

Ich hatte auch so etwas im Hinterkopf, aber ich gab tatsächlich auf genau dieses Design auf. Etwas, das Sie tun können, ist, tatsächliche Listen zu verwenden.

In diesem Fall hätten Sie eine kombinierte Liste, die aus (erstens) einer normalen Liste besteht, die als Puffer fungiert, und (zweitens) einer faulen Liste.

Wenn Sie gegen ein Muster passen mögen, können Sie tun:

match tokens.EnsureBuffer(4) with 
| el1 :: el2 :: remaining    -> (el1.v+el2.v, tokens.SetBuffer(remaining)) 
| el3 :: el4 :: el5 :: el6 :: remaining -> (el1.v-el2.v+el3.v-el4.v, tokens.SetBuffer(remaining)) 

wo EnsureBuffer und Puffersetzen entweder „Token“ mutieren können und zurückgeben oder es zurückgeben, wenn keine Änderung erforderlich ist oder eine neue Instanzen zurückgeben Andernfalls.

Würde das dein Problem lösen? François

Verwandte Themen