나는 클래스 인스턴스에 저장된 데이터 유형 필드 설명에 따라 출력이 달라지는 코드 생성기를 작성하고 있습니다. 그러나, 나는 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를 켜야 할 필요가 있을까요? –