【问题标题】:Scala - implicit macros & materialisationScala - 隐式宏和物化
【发布时间】:2017-03-12 06:13:18
【问题描述】:

隐式宏的用例应该是类型类实例的所谓“物化”。

不幸的是,documentation 中的示例对于如何实现有点模糊。

在被调用时,物化器可以获取 T 的表示并生成 Showable 类型类的适当实例。

假设我有以下特征......

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(",", ",")")
  }
}

和三个测试类

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

现在我明白了,而不是编写以下样板

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})"}

我们应该可以添加

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

  ???
}

object PrettyPrinter{...},然后根据需要生成相应的PrettyPrinters ...如何?我如何真正获得“T 的表示”?

如果我尝试c.typeOf[T],例如,“没有可用于 T 的 TypeTag”。

更新

尝试使用类标签似乎也不起作用。

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

  ???
}

结果

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

更新2

有趣的是,使用 WeakTypeTags 并没有真正改变任何东西

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._

  ???
}

将导致

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

【问题讨论】:

  • 这里不需要宏。它应该只适用于PrettyPrinter.pretty(List(A(2)))
  • @Reactormonk 感谢您的评论。但是,不会因为pretty 找不到PrettyPrinter[A] 的实例。如果您想在评论之前阅读问题,您会注意到使用宏的目的是避免编写样板代码,为每个类定义一个PrettyPrinter。您还会注意到,我对替代的非宏解决方案(如果存在)不感兴趣,因为我提出这个问题是为了更好地理解宏文档中的用例。
  • T: TypeTag - shapeless 使用宏,您可以查看这些用于泛型派生。
  • @Reactormonk 我看不出这有什么帮助。他们只是匹配一个 AST 节点并检查它是否是他们期望的......这与我正在尝试的相反。也许您可以告诉我如何在上面的宏中为T 获取类型标记(或任何可以让我访问类符号)? (见更新)

标签: scala macros implicit-conversion implicit


【解决方案1】:

我如何真正获得“T 的表示”?

您需要使用c.WeakTypeTag,正如您在“更新”部分中找到的编译器消息所暗示的那样。

这个项目有一个你可以修改的工作示例: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, "")
}

【讨论】:

    猜你喜欢
    • 2015-05-07
    • 2019-09-12
    • 1970-01-01
    • 1970-01-01
    • 2020-12-08
    • 2021-08-25
    • 2019-08-12
    • 2022-09-27
    • 1970-01-01
    相关资源
    最近更新 更多