私は、その出力がクラスインスタンスに格納されているデータ型フィールドの説明に依存するコードジェネレータを作成しています。しかし、私は、TH生成の引数で関数を実行する方法を見つけることができません。GHCステージ制限を回避するにはどうすればよいですか?
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
module Generator where
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
data Description = Description String [Description] deriving Show
class HasDescription a where
getDescription :: a -> Description
instance HasDescription Int where
getDescription _ = Description "Int" []
instance (HasDescription a, HasDescription b) => HasDescription (a, b) where
getDescription (_ :: (a, b)) = Description "Tuple2" [getDescription (undefined :: a), getDescription (undefined :: b)]
-- | creates instance of HasDescription for the passed datatype changing descriptions of its fields
mkHasDescription :: Name -> Q [Dec]
mkHasDescription dName = do
reify dName >>= runIO . print
TyConI (DataD cxt name tyVarBndr [NormalC cName types] derives) <- reify dName
-- Attempt to get description of data to modify it.
let mkSubDesc t = let Description desc ds = getDescription (undefined :: $(return t)) in [| Description $(lift $ desC++ "Modified") $(lift ds) |]
let body = [| Description $(lift $ nameBase dName) $(listE $ map (mkSubDesc . snd) types) |]
getDescription' <- funD 'getDescription [clause [wildP] (normalB body) []]
return [ InstanceD [] (AppT (ConT ''HasDescription) (ConT dName)) [getDescription'] ]
別のモジュールが発電機
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
import Generator
data MyData = MyData Int Int
mkHasDescription ''MyData
{- the code I want to generate
instance HasDescription MyData where
getDescription _ = Description "MyData" [Description "IntModified" [], Description "IntModified" []]
-}
を使用しようとすると、エラー
Generator.hs:23:85:
GHC stage restriction: `t'
is used in a top-level splice or annotation,
and must be imported, not defined locally
In the first argument of `return', namely `t'
In the expression: return t
In an expression type signature: $(return t)
編集が表示されます。尋ねるとき
私は問題はちょうど私からといって登場していると考えがTHの中で重要な何かを把握しておらず、いくつかの機能を他のモジュール。
質問の例のように事前計算データを生成することができない場合は、THの理論的な制限についてもっと学びたいと思います。
もちろんlet mkSubDesc t = [| let Description desc ds = getDescription (undefined :: $(return t))
in Description (desC++ "Modified") ds |]
が、これはこれは、生成されたコードの一部になることを意味するが、少なくともこのような場合のために、そのshouldn」:
私が見つけたのは...驚くべきことですが、それはうまくいかないでしょう。おそらくQuasiQuotesを有効にする必要がありますか? –