2014-12-08 14 views
8

Ich möchte ein Angebot in Haskell schreiben. Das Namensargument muss in gen-Funktion übergeben werden, um eine Deklaration zu generieren.QuasiQuote mit Argumenten

quote :: String -> QuasiQuoter 
quote name = QuasiQuoter { 
     quoteExp = undefined, 
     quotePat = undefined, 
     quoteType = undefined, 
     quoteDec = \jsonStr -> gen name (getValue str) 
    } 

Allerdings scheint es, dass ich nicht das Zitat wie dieses

[quote "Hello"| from x to y |] 

Da Haskell erlaubt keine Kursanmeldungen und Zitate können in der gleichen Datei zu sein was ärgerlich ist, was kann ich tun, um ein Argument von außen in das Zitat eingeben?

Antwort

6

Sie haben zwei Möglichkeiten:

  1. Umschaltung $(...) Spleißstellen Verwendung
  2. Ihre Parameter Encode auf den quasi-quoter in der Eingabezeichenfolge.

Mit splice Syntax Ihr Beispiel aussehen würde:

quote :: String -> String -> Q [Dec] 
quote name jsonStr = gen name (getValue jsonStr) 

und Aufrufen es aussieht: $(quote "Hello" "from x to y")

Option 2 zu zeigen, ist hier eine einfache quoter, die mit einem eine Zeichenkette umgibt Zeichen:

import Language.Haskell.TH (litE, stringL) 
import Language.Haskell.TH.Quote 

surround :: QuasiQuoter 
surround = QuasiQuoter 
    { quoteExp = litE . stringL . (\(c:s) -> [c] ++ s ++ [c]) 
    , quotePat = undefined 
    , quoteType = undefined 
    , quoteDec = undefined 
    } 

-- in another file: 
main = print [surround|_some text|] -- prints "_some text_" 

Das erste Zeichen der Eingabezeichenfolge wird als Brac interpretiert Ket-Zeichen zu verwenden. Tatsächlich haben wir einen Char Parameter an eine Funktion vom Typ Char -> QuasiQuoter übergeben.

Für komplexere Parameter oder mehrere Parameter müssen Sie Ihre eigene Syntax und Parser erstellen, um sie zu dekodieren.

Update: Hier ist ein etwas komplexeres Beispiel, bei dem der Aufruf [foo| var xyz|] behandelt var als Name einer Variablen und xyz als Zeichenkette:

-- [foo| var xyz|] is translated to: var ++ "xyz" 

foo :: QuasiQuoter 
foo = QuasiQuoter 
    { quoteExp = go 
    , quotePat = undefined 
    , quoteType = undefined 
    , quoteDec = undefined 
    } 
    where go str = infixE (Just $ varE (mkName var)) 
         (varE $ mkName "++") 
         (Just $ litE (stringL arg1)) 
      where (var:arg1:_) = words str 
+0

Antwort Update Splice Option hinzuzufügen. – ErikR