非常に単純化した意味で、次のようなものがあります。
type Runtime a = {- More or less a StateT on top of an Either monad -}
-- The list of strings in Fn is a bunch of parameter names, the values of
-- which are pushed into the state of the runtime before executing the actual
-- function expr
data Expr = Num Int
| Str T.Text
| Fn [T.Text] (Runtime Expr)
| {- Bunch of other constructors -}
eval :: Expr -> Runtime Expr
parseExp :: Parser Expr
さて、おもちゃの言語に疑似クォーターがあると便利だと判断するまで、テンプレート Haskell を使用したことは一度もありませんでした。
しかし、いずれにせよ、私はそれを少しいじり始め、いくつかのチュートリアルなどに従って、Fn
コンストラクターの扱い方以外は基本的にすべてが簡単であることがわかりました。
Web で情報を収集しているときに、人々が式 quoter を書く一般的な方法を 2 つ見つけました。
- データ型をTH
Expr
:s のインスタンスにしLift
、単純に [| quote |] 解析結果の式 Data
とTypeable
に相当するものを導出し、同じパーサー結果にExpr
適用するdataToExpQ
どちらの場合も、Runtime Expr
. 最初のケースの問題は、実装方法がわからなかったことです。
instance Lift Expr where
lift (Fn ps e) = [| Fn ps ...? |]
(ただし、Data.Text のインスタンスを自分で実装することはできました)。
本当の問題は、私がまだ TH を十分に理解していないことだと思いますが、これまでのところ、チュートリアルや例の量はどれも役に立ちませんでした。
2 番目のケースの問題は、Expr
が のインスタンスにData
なるには、
instance Data (StateT (...) (Either ...) Expr) where
-- Something
私の質問は、これを行う簡単な方法があるかどうかです。それとも、おもちゃの言語の機能がどのように機能するかを再考する必要があるのでしょうか?
後者の場合、モナド内で実行せずに同等の機能を取得する方法に関する推奨事項はありますか? 結局のところ、言語のランタイム環境には状態とエラーの処理が必要なため、これは直感的な解決策のように思えます (これは私が使用しているものEither
です)。