4

非常に単純化した意味で、次のようなものがあります。

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 |] 解析結果の式
  • DataTypeableに相当するものを導出し、同じパーサー結果に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です)。

4

1 に答える 1

4

Exprquasiquoter を構築するために、データ型がリフト可能である必要はありません。この場合、インスタンスを実装することは不可能ですLiftRuntime Exprその理由は、StateT値は本質的に関数であり、関数が何をするかを知る一般的な方法がないため、値の「内部を見る」ことができないためです。

あなたがする必要があるのは、Expr「手で」構築する AST を構築することです。|]-引用符 (または、より具体的には、[| |]-引用符を使用して AST を作成できますが、Exprデータを直接引用することはできません)。

したがって、本質的に、タイプのパーサーが必要です

parseExpQ :: Parser ExpQ

をビルドするために必要な Haskell コードを表すExpを生成しExprます。コンストラクターの場合、 -constructorFnを使用して do ブロックを構築するか、andを使用してバインド チェーンを構築する必要があります。DoEInfixE>>=

これが複雑すぎると思われる場合は、関数本体を式 (おもちゃの言語のセマンティクスによっては、ステートメントのリスト) として表現することもできます。いえ

data Expr = Num Int
          | Str T.Text
          | Fn [T.Text] [Statement]

そして、Statement以前に使用したのと同じ効果を生成するように解釈できるように型を定義しますStateT Either

于 2012-07-20T12:47:18.760 に答える