2014-12-08 25 views
8

我想在Haskell中編寫報價單。名稱參數需要傳入gen函數以生成聲明。帶參數的QuasiQuote

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

然而,似乎我不能使用引號這樣

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

由於哈斯克爾不允許報價申報和報價是在這惱人的同一個文件,我能做些什麼來從外面傳遞一個論點到引文中?

回答

6

你有兩個選擇:

  1. 切換到使用接頭$(...)
  2. 編碼您的參數輸入字符串準報價者。

隨着拼接語法的例子看起來像:

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

並調用它看起來像:$(quote "Hello" "from x to y")

爲了演示選項2,這裏是一個簡單的加引號包圍文字串用字符:

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

輸入字符串的第一個字符被解釋爲brac要使用的字符。實際上,我們已將Char參數傳遞給Char -> QuasiQuoter類型的函數。

對於更復雜的參數或多個參數,您將不得不創建自己的語法和解析器來解碼它們。

更新:這裏有一個稍微複雜的例子,其中調用[foo| var xyz|]對待var作爲變量的名稱和xyz爲文字字符串:

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

答案更新添加拼接選項。 – ErikR 2014-12-08 06:21:12