標準の 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 |]
またはこれに似たもの。
私が書いたquasiquoterはここにあります:
{-# 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 |]
2つのエラーが残ります:
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 |]
| ^^^^^^^^^^^^^^^^^^^^
quoteDec
の代わりにquasiquoter を使用するにはどうすればよい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