次のようにコードを並べ替えると、機能します。
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data None = None { _f :: Int }
type Simpl = Env
type Env = Int
makeLenses ''None
Template Haskell splices を使用して新しいトップレベルの宣言をコードに追加すると、コードmakeLenses
内の宣言の順序が突然重要になります!
その理由は、通常、Haskell プログラムをコンパイルするには、最初にすべてのトップレベルの宣言を収集し、それらを内部で並べ替えて依存関係の順序に並べ替え、次にそれらを 1 つずつ (または相互に再帰的な宣言の場合はグループごとに) コンパイルする必要があるためです。
任意のコードを実行することによって新しい宣言が導入されます。GHC はどの宣言makeLenses
を実行する必要があるのか わからないためです。そのため、ファイル全体を依存関係の順序に並べることはできず、少なくともスプライスの前または後に宣言を行うかどうかを決定するために、あきらめてユーザーが自分でそれを行うことを期待しています。
これを説明している唯一のオンライン リファレンスは、元の Template Haskell paperのセクション 7.2 で、アルゴリズムは次のようになっています。
[d1,...,da]
splice ea
[da+2,...,db]
splice eb
...
splice ez
[dz+2,...,dN]
ここで、 splice 宣言は明示的に示されたものだけであるため、各 group[d1,...,da]
などはすべて通常の Haskell 宣言になります。
- 最初のグループに対して、従来の依存関係分析を実行し、続いて型チェックを実行します。その自由変数はすべてスコープ内にある必要があります。
したがって、ここでの問題は、スプライスの前の宣言の最初のグループが、スプライスの後の 2 番目のグループとは別に処理され、 の定義が見えないことですEnv
。
私の一般的な経験則は、可能であればこのようなスプライスをファイルの最後に置くことですが、これが常に機能するという保証はないと思います.