2014-12-08 40 views
8

Chcę napisać ofertę w Haskell. Argument name musi zostać przekazany do funkcji gen w celu wygenerowania deklaracji.QuasiQuote z argumentami

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

Wydaje się jednak, że nie mogę użyć cytat jak ten

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

Od Haskell nie pozwala deklaracje cytat i cytaty, aby być w tym samym pliku, co jest irytujące, co mogę zrobić, aby przekazać argument z zewnętrznej strony do cytatu?

Odpowiedz

6

Masz dwie opcje:

  1. przełączyć się za pomocą spawów $(...),
  2. zakodować parametr do quasi-Quoter w ciągu wejściowego.

ze składnią spawów Twój przykład wyglądałby następująco:

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

i powołując wygląda: $(quote "Hello" "from x to y")

Aby wykazać opcję 2, tutaj jest prosta Quoter który otacza ciągiem znaków z postać:

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_" 

Pierwszy znak ciąg wejściowy jest interpretowany jako brac ket postać do użycia. W efekcie przekazaliśmy parametr Char do funkcji typu Char -> QuasiQuoter.

Aby uzyskać bardziej złożone parametry lub wiele parametrów, należy utworzyć własną składnię i analizator składni w celu ich odkodowania.

Aktualizacja: Tu jest nieco bardziej złożony przykład gdzie pw [foo| var xyz|] traktuje var jako nazwa zmiennej i xyz jako dosłowne wyrażenie: zmiana

-- [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

Odpowiedź dodać opcję spawów. – ErikR