2015-08-24 4 views
10

Also ich möchte einen Typ, der Bäume mit einer Reihe von Node-Typen darstellt. Ich möchte auch Typen, die einen ähnlichen Baum darstellen, der über überlappende Sätze definiert ist. Dies ist eine andere Version des AST-Problems. Sagen, dass mein Pool von Knoten-Typ ist:Wie kann ich syntaktisches Durcheinander reduzieren, wenn ich in Haskell einen polymorphen Baum markiere?

data Lit = Lit Int 
data Var = Var String 
data Hole = Hole Int 

Ein Parse-Baum Lit s oder Var s aber keine Hole s enthalten. Ein zweiter Baum, genannt Template, kann Lit s, Var s oder Hole s enthalten.

Um die Dinge einfach zu halten, gibt es einen einzigen rekursiven Knoten Typ Add.

data Parse = A Lit | B Var 
data Template = C Lit | D Var | E Hole 
data Tree a = Leaf a 
      | Add (Tree a) (Tree a) 

So, jetzt kann ich Daten erklären, und ich kann auf sie noch muster Spiel, das einzige Problem ist die syntaktische Unordnung.

aParse = Add (A Lit 3) (B Var "x") 
aTemplate = Add (C Lit 4) (E Hole 3) 
fun (Add (A lit) (B var) = ... 

Was würde Ich mag es, etwas Zucker ähnlich ist:

ParseLit = A . Lit 
TempLit = C . Lit 

Offensichtlich Aliase für Zusammensetzungen von Konstrukteuren (nicht-Typ) ist in Haskell nicht legal. Aber was ist der sauberste Weg, dies zu schreiben und so viel Kesselplatte wie möglich zu vermeiden?

Antwort

14

Die Spracherweiterung PatternSynonyms kann hier helfen. Damit können Sie Aliase für Muster festlegen:

{-# LANGUAGE PatternSynonyms #-} 

pattern ParseLit x = A (Lit x) 

someFunc :: Parse -> Int 
someFunc p = case p of 
    ParseLit x -> x 
    _ -> 0 

Es gibt zwei Arten von Mustern Synonyme: bidirektional (wie im Beispiel) und unidirektional. Die bidirektionalen können auch als Konstruktoren verwendet werden:

*Main> :t ParseLit 
ParseLit :: Int -> Parse 

*Main> ParseLit 77 
+0

Oh wow. Genau das habe ich gesucht. Vielen Dank. – Amoss

Verwandte Themen