简体   繁体   English

从宏中的 HList 获取类型序列

[英]Get sequence of types from HList in macro

Context : I'm trying to write a macro that is statically aware of an non-fixed number of types.上下文:我正在尝试编写一个静态感知非固定数量类型的宏。 I'm trying to pass these types as a single type parameter using an HList .我正在尝试使用HList将这些类型作为单个类型参数HList It would be called as m[ConcreteType1 :: ConcreteType2 :: ... :: HNil]() .它将被称为m[ConcreteType1 :: ConcreteType2 :: ... :: HNil]() The macro then builds a match statement which requires some implicits to be found at compile time, a bit like how a json serialiser might demand implicit encoders.宏然后构建一个 match 语句,它需要在编译时找到一些隐式,有点像 json 序列化器可能需要隐式编码器。 I've got a working implementation of the macro when used on a fixed number of type parameters, as follows:当在固定数量的类型参数上使用时,我有一个宏的工作实现,如下所示:

def m[T1, T2](): Int = macro mImpl[T1, T2]

def mImpl[T1: c.WeakTypeTag, T2: c.WeakTypeTag](c: Context)(): c.Expr[Int] = {
  import c.universe._
  val t = Seq(
    weakTypeOf[T1],
    weakTypeOf[T2]
  ).map(c => cq"a: $c => externalGenericCallRequiringImplicitsAndReturningInt(a)")
  val cases = q"input match { case ..$t }"
  c.Expr[Int](cases)
}

Question : If I have a WeakTypeTag[T] for some T <: HList , is there any way to turn that into a Seq[Type] ?问题:如果我有一些T <: HListWeakTypeTag[T] ,有没有办法把它变成Seq[Type]

def hlistToSeq[T <: HList](hlistType: WeakTypeTag[T]): Seq[Type] = ???

My instinct is to write a recursive match which turns each T <: HList into either H :: T or HNil , but I don't think that kind of matching exists in scala.我的本能是编写一个递归匹配,将每个T <: HList转换为H :: THNil ,但我认为 scala 中不存在这种匹配。

I'd like to hear of any other way to get a list of arbitrary size of types into a macro, bearing in mind that I would need a Seq[Type] , not Expr[Seq[Type]] , as I need to map over them in macro code.我想听听任何其他方式将任意大小的类型列表放入宏中,记住我需要Seq[Type] ,而不是Expr[Seq[Type]] ,因为我需要映射在宏代码中覆盖它们。

A way of writing a similar 'macro' in Dotty would be interesting too - I'm hoping it'll be simpler there, but haven't fully investigated yet.一种在 Dotty 中编写类似“宏”的方法也很有趣——我希望它会更简单,但还没有完全调查清楚。

Edit (clarification) : The reason I'm using a macro is that I want a user of the library I'm writing to provide a collection of types (perhaps in the form of an HList ), which the library can iterate over and expect implicits relating to.编辑(澄清) :我使用宏的原因是我希望我正在编写的库的用户提供类型集合(可能以HList的形式),库可以迭代并期望隐含相关。 I say library, but it will be compiled together with the uses, in order for the macros to run;我说的是库,但它会和用途一起编译,以便宏运行; in any case it should be reusable with different collections of types.在任何情况下,它都应该可以在不同类型的集合中重用。 It's a bit confusing, but I think I've worked this bit out - I just need to be able to build macros that can operate on lists of types.这有点令人困惑,但我想我已经解决了这一点 - 我只需要能够构建可以对类型列表进行操作的宏。

Currently you seem not to need macros.目前您似乎不需要宏。 It seems type classes or shapeless.Poly can be enough.似乎 type classes 或shapeless.Poly就足够了。

def externalGenericCallRequiringImplicitsAndReturningInt[C](a: C)(implicit 
  mtc: MyTypeclass[C]): Int = mtc.anInt

trait MyTypeclass[C] {
  def anInt: Int
}
object MyTypeclass {
  implicit val mtc1: MyTypeclass[ConcreteType1] = new MyTypeclass[ConcreteType1] {
    override val anInt: Int = 1
  }

  implicit val mtc2: MyTypeclass[ConcreteType2] = new MyTypeclass[ConcreteType2] {
    override val anInt: Int = 2
  }

  //...
}

val a1: ConcreteType1 = null
val a2: ConcreteType2 = null
externalGenericCallRequiringImplicitsAndReturningInt(a1) //1
externalGenericCallRequiringImplicitsAndReturningInt(a2) //2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM