如何“应用”模板Haskell中的类型变量?

时间:2018-10-22 18:26:33

标签: haskell template-haskell

我正在将具有以下结构的记录传递给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。所以,我的问题是:

  • 如何在TH中“应用”此类型变量
  • 或者,如何在将其传递给TH之前应用 。我尝试了$(myTHFunction ''(MyRecord SomeSelector)),但这没用。

1 个答案:

答案 0 :(得分:1)

这似乎有两个问题:

  1. 您想知道如何在类型中替换自由类型变量。

    我知道的最好方法是使用th-abstraction包中的applySubstitution,它还有助于跨GHC版本的数据类型的规范化表示,因此您不必将自己束缚于一个版本的Template Haskell。

  2. 您想知道如何使用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 ...进行一些细化以提取正确的信息。