我们有以下类型类
trait Mapper[A,M[_]]{
def map[B](a:M[A], f:A => B):M[B]
}
我们希望为特定的M提供实例。天真的实现将如下所示:
def materializeMapperImpl[A : c.WeakTypeTag,M[_]](c:blackbox.Context)(implicit mTypeTag:c.WeakTypeTag[M[A]]): c.Expr[Mapper[A,M]] = {
import c.universe._
val aType = weakTypeOf[A]
//println(mTypeTag.toString())
c.Expr[Mapper[A,M]]{
q"""
new Mapper[$aType,$mTypeTag]{
def map[B](a1:$mTypeTag, f: $aType => B): $mTypeTag = {
???
}
}
"""
}
}
但是,这不会编译,因为mTypeTag
在其通用参数中没有被细化,而是看起来像List
而不是List[Int]
和List[String]
。我们如何细化mTypeTag,将其参数设置为宏中的A和B?
答案 0 :(得分:1)
package so
import scala.language.experimental.macros
import scala.language.higherKinds
import scala.reflect.macros.blackbox
trait Mapper[A, M[_]] {
def map[B](a: M[A], f: A => B): M[B]
}
object Mappers {
def f[A, M[_]]: Mapper[A, M] = macro impl[A, M]
def impl[A, M[_]](c: blackbox.Context)
(implicit
a: c.WeakTypeTag[A],
m: c.WeakTypeTag[M[_]]
): c.Tree = {
import c.universe._
val ma = m.tpe match {
case TypeRef(pre, sym, args) =>
import compat._
TypeRef(pre, sym, List(a.tpe))
}
//attention it is : new packageName.className {}
val tree =
q"""
new so.Mapper[${a.tpe},$m]{
override def map[B](a:$ma,f:($a) => B) = ???
}
"""
q"$tree"
}
}
//测试
Mappers.f[Int,Option]