Scala - implicit macros & materialisation

寵の児 提交于 2020-01-06 15:17:17

问题


The use cases for implicit macros is supposed to be the so-called "materialisation" of type class instances.

Unfortunately, the example in the documentation is a bit vague on how that is achieved.

Upon being invoked, the materializer can acquire a representation of T and generate the appropriate instance of the Showable type class.

Let's say I have the following trait ...

trait PrettyPrinter[T]{
  def printed(x:T) : String
}
object PrettyPrinter{
  def pretty[T](x:T)(implicit pretty:PrettyPrinter[T]) = pretty printed x

  implicit def prettyList[T](implicit pretty :PrettyPrinter[T]) = new PrettyPrinter[List[T]] {
    def printed(x:List[T]) = x.map(pretty.printed).mkString("List(",", ",")")
  }
}

and three test classes

class A(val x:Int)
class B(val x:Int)
class C(val x:Int)

Now I understand that instead of writing the following boilerplate

implicit def aPrinter = new PrettyPrinter[A] {def printed(a:A) = s"A(${a.x})"}
implicit def bPrinter = new PrettyPrinter[B] {def printed(b:B) = s"B(${b.x})"}
implicit def cPrinter = new PrettyPrinter[C] {def printed(c:C) = s"C(${c.x})"}

we should be able to add

implicit def materialise[T] : PrettyPrinter[T] = macro implMaterialise[T]
def implMaterialise[T](c:blackbox.Context):c.Expr[PrettyPrinter[T]] = {
  import c.universe._

  ???
}

to the object PrettyPrinter{...} which then generates the corresponding PrettyPrinters on demand ... how? How do I actually get that "representation of T"?

If I try c.typeOf[T], for example, "No TypeTag available for T".

UPDATE

Trying to use class tags doesn't seem to work either.

implicit def materialise[T:ClassTag] : PrettyPrinter[T] = macro implMaterialise[T]
def implMaterialise[T:ClassTag](c:blackbox.Context):c.Expr[PrettyPrinter[T]] = {
  import c.universe._

  ???
}

results in

Error:(17, 69) macro implementations cannot have implicit parameters other than WeakTypeTag evidences
implicit def materialise[T:ClassTag] : PrettyPrinter[T] = macro implMaterialise[T]
                                                                ^

update2

Interestingly, using WeakTypeTags doesn't really change anything as

implicit def materialise[T:WeakTypeTag]: PrettyPrinter[T] = macro implMaterialise[T]
def implMaterialise[T](c:blackbox.Context)(implicit evidence : WeakTypeTag[T]):c.Expr[PrettyPrinter[T]]
= {
  import c.universe._

  ???
}

will result in

Error:(18, 71) macro implementations cannot have implicit parameters other than WeakTypeTag evidences
implicit def materialise[T:WeakTypeTag]: PrettyPrinter[T] = macro implMaterialise[T]
                                           ^

回答1:


How do I actually get that "representation of T"?

You need to use c.WeakTypeTag, as hinted at by the compiler message you found in your "UPDATE" section.

This project has a working example that you can adapt: https://github.com/underscoreio/essential-macros/blob/master/printtype/lib/src/main/scala/PrintType.scala

object PrintTypeApp extends App {
  import PrintType._

  printSymbol[List[Int]]
}

import scala.language.experimental.macros

import scala.reflect.macros.blackbox.Context
import scala.util.{ Try => ScalaTry }

object PrintType {
  // Macro that generates a `println` statement to print
  // declaration information of type `A`.
  //
  // This only prints meaningful output if we can inspect
  // `A` to get at its definition:
  def printSymbol[A]: Unit =
    macro PrintTypeMacros.printTypeSymbolMacro[A]
}

class PrintTypeMacros(val c: Context) {
  import c.universe._

  def printTypeSymbolMacro[A: c.WeakTypeTag]: c.Tree =
    printSymbol(weakTypeOf[A].typeSymbol, "")
}


来源:https://stackoverflow.com/questions/40320547/scala-implicit-macros-materialisation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!