1

標準の 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

4

1 に答える 1

3

残念ながら、トップレベルの宣言では宣言の準引用符しか使用できません。ドキュメントから:

準引用符が代わりに表示される場合があります

  • 表現
  • パターン
  • タイプ
  • トップレベルの宣言

TH を使用する代わりに、次の使用を検討できますOverloadedStrings

instance IsString Variable where
  fromString str = Var (pack str)

maxQuery :: Query MAX
maxQuery = match
         ( "sch" `isa` "school"
         $ forWhich "ranking" `labelMatches` "ran" $ε)
         `get` ["ran"]
         `max` ["ran"]
于 2021-06-09T10:29:47.860 に答える