我正在实现一个基于使用标准haskell 函数/组合器来构建数据库查询的DSL。从实现 POV 中,我决定在查询中表示变量,如下所示:
newtype Variable = Var { fromVar :: Text }
然而,这迫使用户Var "something"
经常写作,所以我决定编写一个自动执行此操作的 quasiquoter。
这是 DSL 的一个示例:
{-# LANGUAGE OverloadedStrings #-}
maxQuery :: Query MAX
maxQuery = match
( sch `isa` "school"
$ forWhich "ranking" `labelMatches` ran $ε)
`get` [ran]
`max` [ran]
where
[sch,ran] = map Var ["sch","ran"]
我希望它是什么:
maxQuery :: Query MAX
maxQuery = match
( sch `isa` "school"
$ forWhich "ranking" `labelMatches` ran $ε)
`get` [ran]
`max` [ran]
where [defVars| sch ran |]
或类似的东西。
我写的准引用者在这里:
{-# LANGUAGE TemplateHaskell #-}
module TypeDBTH where
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Quote
import Data.List.Split
import Data.Text (pack)
mkVars :: [String] -> Dec
mkVars vars = ValD
(ListP (map (VarP . mkName) vars))
(NormalB (ListE (map (\v -> AppE (ConE $ mkName "Var")
$ AppE (VarE $ mkName "pack")
(LitE $ StringL v))
vars)))
[]
defVars :: QuasiQuoter
defVars = QuasiQuoter { quoteDec = quoteVars }
--, quoteExp = expQuoteVars }
quoteVars :: String -> Q [Dec]
quoteVars = return . return . mkVars . filter (/= "") . splitOn " "
expQuoteVars :: String -> Q Exp
expQuoteVars s = return $ LetE [(mkVars . filter (/= "") . splitOn " " $ s)] (LitE $ StringL "x")
原来我只写quoteVars
。为了在 ghci 中进行测试,我添加了expQuoteVars
. 但是,现在删除后一个并尝试编写
...
where [defVars| sch ran |]
给我留下两个错误:
lib/TypeDBQuery.hs:806:1: error:
parse error (possibly incorrect indentation or mismatched brackets)
因为where [quasiquoter]
之后一无所有
和
lib/TypeDBQuery.hs:807:5: error:
• Exception when trying to run compile-time code:
lib/TypeDBTH.hs:18:11-46: Missing field in record construction quoteExp
Code: Language.Haskell.TH.Quote.quoteExp defVars " sch ran "
• In the quasi-quotation: [defVars| sch ran |]
|
807 | x = [defVars| sch ran |]
| ^^^^^^^^^^^^^^^^^^^^
我如何使用 quasiquoterquoteDec
代替a quoteExp
?这可能吗?
如果这样更容易,我也愿意像这样使用它:
maxQuery :: Query MAX
maxQuery = let [defVars | sch ran |] in
$ match
( sch `isa` "school"
$ forWhich "ranking" `labelMatches` ran $ε)
`get` [ran]
`max` [ran]
我查看了 wiki.haskell.org 和 TH 模块的“教程”和信息站点,但无法弄清楚如何做到这一点...... https://wiki.haskell.org/Template_Haskell#What_to_do_when_you_can.27t_splice_that_there https ://wiki.haskell.org/Quasiquotation https://wiki.haskell.org/A_practical_Template_Haskell_Tutorial