我有一个方法,接受一个 HList
并使用它来构建一个类的实例。
我想提供一些简化的语法,隐藏显式的 cons。所以我想从以下语法转换:
MyThingy.describe( 42 :: true :: "string" :: HNil)
to
MyThingy.describe {
42
true
"string"
}
当定义 MyThingy
如下时:
class MyThingy[L <: HList](elems: L)
我尝试使用这个宏
def describe[L <: HList](elements: Unit): MyThingy[L] = macro MyThingyMacros.describeImpl[L]
并且
def describeImpl[L <: shapeless.HList : c.WeakTypeTag](c: Context)(elems: c.Tree): c.Tree = {
import c.universe._
def concatHList: PartialFunction[Tree, Tree] = {
case Block(l, _) =>
val els = l.reduceRight((x, y) => q"shapeless.::($x,$y)")
q"$els :: shapeless.HNil"
}
concatHList.lift(elems) match {
case None => c.abort(c.enclosingPosition, "BOOM!")
case Some(elemsHList) =>
val tpe = c.typecheck(elemsHList).tpe
q"new MyThingy[$tpe]($elemsHList)"
}
}
但是类型检查器出现了问题:
宏展开期间发生异常: scala.reflect.macros.TypecheckException: 推断的类型参数 [Int,Boolean] 不符合方法 apply 的类型参数边界 [H,T <: shapeless.HList]
显然编译器正在尝试从宏展开前的块中推断 [Int, Boolean]
。我也不明白为什么它需要两个参数,而 describe
和 MyThing
只需要一个。
有没有一种方法可以通过宏生成的树来驱动类型推断?