準引用符を使用すると、コンパイル中にASTコードを生成できますが、生成されたコードは、準引用符が書き込まれた場所に挿入されます。コンパイル時に生成されたコードを他の場所に挿入することは可能ですか?たとえば、QQが書かれたものとは異なる特定のモジュールファイルでは?ハードコードされたモジュール構造に依存しますが、それは問題ありません。
それがQQで不可能であるが、誰かがそれを達成するための別の方法を知っているなら、私は提案を受け入れます。
準引用符を使用すると、コンパイル中にASTコードを生成できますが、生成されたコードは、準引用符が書き込まれた場所に挿入されます。コンパイル時に生成されたコードを他の場所に挿入することは可能ですか?たとえば、QQが書かれたものとは異なる特定のモジュールファイルでは?ハードコードされたモジュール構造に依存しますが、それは問題ありません。
それがQQで不可能であるが、誰かがそれを達成するための別の方法を知っているなら、私は提案を受け入れます。
これに答えるには、準引用符が何であるかを知ることが役立ちます。GHCドキュメントから、準引用符は次の値です。
data QuasiQuoter = QuasiQuoter { quoteExp :: String -> Q Exp,
quotePat :: String -> Q Pat,
quoteType :: String -> Q Type,
quoteDec :: String -> Q [Dec] }
つまり、任意の文字列から、式、パターン、型、および宣言のそれぞれのテンプレートHaskell表現である、、、、およびの1つ以上ExpQ
へのパーサーです。PatQ
TypeQ
DecQ
準引用符を使用する場合、GHCはパーサーを文字列に適用してExpQ
(または他のタイプ)を作成し、結果のテンプレートhaskell式をスプライスして実際の値を生成します。
TH式にアクセスできるように、準クォートの構文解析とスプライシングを分離するように求めているようです。次に、その式を別のモジュールにインポートして、そこで自分でスプライスできます。
準引用符のタイプを知っていると、これが可能であることがすぐにわかります。通常、QQを次のように使用します
-- file Expr.hs
eval :: Expr -> Integer
expr = QuasiQuoter { quoteExp = parseExprExp, quotePat = parseExprPat }
-- file Foo.hs
import Expr
myInt = eval [expr|1 + 2|]
代わりに、パーサーを自分で抽出し、TH式を取得して、後でスプライスすることができます。
-- file Foo.hs
import Expr
-- run the QQ parser
myInt_TH :: ExpQ
myInt_TH = quoteExp expr "1 + 2"
-- file Bar.hs
import Foo.hs
-- run the TH splice
myInt = $(myInt_TH)
もちろん、これをすべて自分で書いている場合は、準引用符をスキップして、パーサーとテンプレートHaskellを直接使用できます。どちらにしてもほとんど同じです。