4

次のコードを検討してください。

マジック :: 文字列 -> Q Exp
マジック s = [e| putStrLns |]

さて、私が知る限り、これは実際には機能しないはずです。オックスフォード ブラケットの内側はs対象外です。それでも、上記は明らかに完全に機能します。

この例を少し変更すると、ひどく壊れます。

マジック :: Exp -> Q Exp
マジック (VarE n) = [e| putStrLn (nameBase n) |]

前と同じように、スコープ外の変数があります。そして今度は壊れる。しかし、スコープ外の変数については文句を言いません。代わりに、インスタンスがない文書化されていないクラスについて泣き言を言います。

いったい何が起こっているのか知っている人はいますか?

4

2 に答える 2

12

s オックスフォード括弧内の範囲です基本的に、複数の型 (Liftインスタンスを持つもの) の値を引用符で囲まれた式の中で使用することが許可されており、それらは自動的に適切なコードに変換され、対応する値を反対側で再作成します。

たとえば、sのLiftインスタンスIntegerは対応する整数リテラルを構築するだけであり、 のインスタンスMaybeは適切なコンストラクター アプリケーションを構築するだけです。の独自のインスタンスを定義することもできますLift

ができないため、「インスタンスなし」エラーが発生しnます。NameLift

于 2012-03-06T17:19:15.197 に答える
2

簡単な答えは、引用括弧が(ある意味で)ローカル変数をキャプチャするため、魔法の関数が機能することが期待されるということだと思います。基本的に、引用括弧内のコンパイル時のローカル変数は、そのリテラル値に置き換えられ、実行時の定数になります。これは、リフト関数を暗黙的に呼び出すことによって実現されます。.. var .. |] は [| になります。$(リフト変数) |]。

おそらく、この動作を、同じ引用符を繰り返し呼び出しても互いの変数名に干渉しないように、ローカル変数を一意にキャプチャするという事実と混同している可能性があります。これは、舞台裏で newName を呼び出すことによって実現され、一意の変数名が保証されます。

それが役立つ場合、私は個人的に引用括弧を「スプライスジェネレーター」と考えています。これは、コンパイル時に AST に変換される Haskell コードの小さな断片であり、したがって、どこにでも挿入できるスプライスになります。Bulat のチュートリアル (からのリンク) で指摘されているように、コードを生成する Haskell 関数と、haskell コードから TH AST への単純な自動変換が混在しているため、これらはマクロ プリプロセッサの形式のように機能します。

編集:答えに勝ったようです-追加の価値がある場合に備えて、答えを残しています。

于 2012-03-06T17:22:14.450 に答える