我正在将具有以下结构的记录传递给Template Haskell函数:
module Editor.App where
data WithMaybe
data WithoutMaybe
type family TypeSelector a b where
TypeSelector WithMaybe b = Maybe b
TypeSelector WithoutMaybe b = b
data MyRecord a = MyRecord
{ field1 :: TypeSelector a Int
, field2 :: TypeSelector a String
}
$(myTHFunction ''MyRecord)
在myTHFunction
内部,我打电话给reify
,它正确地给了我以下类型-Info
:
TyConI
(DataD
[]
Editor.App.MyRecord
[KindedTV a_6989586621679348600 StarT]
Nothing
[RecC Editor.App.MyRecord
[ ( Editor.App.field1
, Bang NoSourceUnpackedness NoSourceStrictness
, AppT (AppT (ConT Editor.App.TypeSelector) (VarT a_6989586621679348600))
(ConT GHC.Types.Int) )
, ( Editor.App.field2
, Bang NoSourceUnpackedness NoSourceStrictness
, AppT (AppT (ConT Editor.App.TypeSelector) (VarT a_6989586621679348600))
(ConT GHC.Base.String) )
]
]
[]
)
但是,在我的应用程序逻辑中,我无法继续执行未应用的KindedTV a_6989586621679348600 StarT
。所以,我的问题是:
$(myTHFunction ''(MyRecord SomeSelector))
,但这没用。答案 0 :(得分:1)
这似乎有两个问题:
您想知道如何在类型中替换自由类型变量。
我知道的最好方法是使用th-abstraction
包中的applySubstitution
,它还有助于跨GHC版本的数据类型的规范化表示,因此您不必将自己束缚于一个版本的Template Haskell。
您想知道如何使用TH而不是单个名称来传递应用类型。
引用的语法-即'ValueName
或''TypeName
-引号名称,它们仅对应于对绑定的引用。 MyRecord SomeSelector
显然不是名字,而是一种类型。因此,应该使用类型引号语法代替写为[t|MyRecord SomeSelector|]
的名称引号语法。此引用将为您提供类型Language.Haskell.TH.Syntax.Type
的值,该值是一种结构化的数据类型,表示任意Haskell类型的AST。
据我所知,在某个库中没有写下任何函数,您无法直接从形状为Type
的{{1}}到与{{1 }},其参数变量以类型T X ...
实例化。当然,这是一个部分函数:T
引用有效的X ...
,但它的形状不是[t|forall a. a|]
,因此您必须自己处理该故障模式(并且希望报告有用的错误消息)。可以根据Type
来定义它,而无需花费太多的精力,但是您将不得不对收到的T X ...
进行一些细化以提取正确的信息。