如何在准报价宏中精炼通用的WeakTypeTag

时间:2017-09-12 22:13:03

标签: scala macros scala-macros

我们有以下类型类

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?

1 个答案:

答案 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]