`将`a类型提升到模板Haskell`TypeQ中`

`将`a类型提升到模板Haskell`TypeQ中`,haskell,metaprogramming,template-haskell,Haskell,Metaprogramming,Template Haskell,如果我有一个值(属于的实例类型),我可以使用lift创建计算结果为该值的术语的模板Haskell表示 有类似的类型吗?举个小例子,假设我想写 foo :: (SomeAppropriateConstraintOn a) => proxy a -> ExpQ foo pa = [| \x -> (x :: $(liftType pa)) |] 如何编写此函数 中提到的一个想法是使用a的TypeRep。然而,这并不像线程听起来那么简单。下面是我尝试过的:一个函数,它通过递归地将t

如果我有一个值(属于的实例类型),我可以使用
lift
创建计算结果为该值的术语的模板Haskell表示

有类似的类型吗?举个小例子,假设我想写

foo :: (SomeAppropriateConstraintOn a) => proxy a -> ExpQ
foo pa = [| \x -> (x :: $(liftType pa)) |]
如何编写此函数

中提到的一个想法是使用
a
TypeRep
。然而,这并不像线程听起来那么简单。下面是我尝试过的:一个函数,它通过递归地将tycon名称包装在
ConT
中,将
TypeRep a
转换为模板Haskell
Type

{-# LANGUAGE PolyKinds #-}

import Type.Reflection
import Language.Haskell.TH as TH

liftTypeRep :: TypeRep a -> TH.Type
liftTypeRep ty = foldl AppT t0 [liftTypeRep ty' | SomeTypeRep ty' <- args]
  where
    (con, args) = splitApps ty
    t0 = ConT $ mkName (tyConModule con <> "." <> tyConName con)
现在,如果我尝试
liftTypeRep
Foo 42的
TypeRep
,我会得到一个无意义的类型:

{-# LANGUAGE DataKinds, GADTs #-}
{-# LANGUAGE TemplateHaskell, QuasiQuotes #-}

import Type.Reflection

test = $([| MkFoo :: $(pure $ liftTypeRep (typeRep :: TypeRep (Foo 42))) |])
错误消息是:

liftTypeRep.hs:8:10: error:
    • Illegal type constructor or class name: ‘42’
      When splicing a TH expression:
        Foo.MkFoo :: Foo.Foo (GHC.TypeLits.42)
    • In the untyped splice:
        $([| MkFoo ::
               $(pure $ liftTypeRep (typeRep :: TypeRep (Foo 42))) |])
  |
8 | test = $([| MkFoo :: $(pure $ liftTypeRep (typeRep :: TypeRep (Foo 42))) |])
  |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
如果我们打印拼接,它显然是错误的:

SigE (ConE Foo.MkFoo) (AppT (ConT Foo.Foo) (ConT GHC.TypeLits.42))

有人问我这个问题,我最终写信来满足这个需求

它最终有点麻烦,因为我们需要从类型字符串中解析出它是什么类型。easy case适用于大多数类型-常规类型构造函数、函数,甚至是升级的数据构造函数(例如
'True
)。我在库中编写了一些测试,主要涉及用例

代码如下:

liftType::forall t。Typeable t=>Type
提升类型=
go(typeRep@t)
哪里
go::对于所有k(a::k)。typerepa->Type
去吧=
案例tr
康泰康->
mk泰康
应用程序传输trB->
附件(go trA)(go trB)
趣味交通-trB->
续“”(>)`AppT`go-trA`AppT`go-trB
mk::泰康->类型
mk泰康=
让
tcName=
泰康名称泰康
在里面
如果黑斯迪克的名字
然后
让
名称库=
mkOccName(删除1个tcName)
名字=
名称基风味
在里面
推广名称
否则,如果有数字tcName,则
LitT(NumTyLit(读tcName))
否则,如果您的姓名是
LitT(StrTyLit(stripName))
其他的
让
名称库=
mkOccName tcName
风味=
命名
TcClsName
(mkPkgName$tyConPackage tyCon)
(mkModName$tyConModule tyCon)
名字=
名称基风味
在里面
连续名称
stripQuotes xs=
案例xs
[] ->
[]
(“”:rest)->
反向(stripQuotes(反向rest))
_ ->
xs
hasTick=前缀满足('\''==)
hasDigit=前缀满足isDigit
hasQuote=前缀满足(“”==)
isList=(“'[]”=)
前缀化::(Char->Bool)->[Char]->Bool
前缀化pxs=
案例xs
a:——>
通讯社
_ ->
假的

有关完整的导入和扩展,请参阅Hackage上的源代码。

?@n.“代词m”。我认为没有足够的细节。从一个
TypeRep a
开始是一个好主意,但它并不像将
AppT
折叠到
splitApps
那样简单:但这一想法限制了类型级的文字,例如
8192
@n.“代词m”。毫无疑问,
ConT“TypeLits.42”
并不是一个很好的表示,因为这正是
LitT
构造函数的作用。是的,但是您如何知道何时使用
ConT
以及何时使用
LitT
?如果它是一个整数,你可以
显示它并解析它…@n.'m。是的,没错。因此,问题就来了。它不应该被称为
Language.Haskell.TH.LiftType
?如果可能的话,我更喜欢较短的模块名。
SigE (ConE Foo.MkFoo) (AppT (ConT Foo.Foo) (ConT GHC.TypeLits.42))