在Scala 3宏内部提供与类型参数[T]等效的内容。

huangapple go评论69阅读模式
英文:

Providing the equivalent of a type parameter [T] from inside a Scala 3 macro

问题

I apologize for the inconvenience, but it seems that your provided code is already in English, and there is no need for translation. If you have any specific questions or need assistance with the code, please feel free to ask, and I'll be happy to help.

英文:

I'm, um, a very naive Scala 3 metaprogrammer. Apologies in advance.

I'm trying to canonicalize type names. Calling _.dealias.simplified.show on a TypeRepr does the job just fine on the base type, but it doesn't touch the type parameters. So, I'd like to iterate through the type params and call my canonicalizer on them recursively. After some trial and error and reading great intros by Adam Warsky and Eugene Yokota I've managed to iterate through the type params, but I can't figure out how to make the recursive call.

object Playpen:
  import scala.quoted.*

  inline def recursiveCanonicalName[T]: String = ${Playpen.recursiveCanonicalNameImpl[T]}

  def recursiveCanonicalNameImpl[T](using q : Quotes)( using tt : Type[T]) : Expr[String] =
    import quotes.reflect.*
    val repr = TypeRepr.of[T]
    repr.widenTermRefByName.dealias match
      case AppliedType(name, args) =>
        Expr(name.dealias.simplified.show + "[" + args.map(a => a.dealias.simplified.show /*(recursiveCanonicalNameImpl(q)(a.asType)*/).mkString(",") + "]")
      case _ =>
        Expr(repr.dealias.simplified.show)

The current version "works" to canonicalize one level of type params, but without recursion can't go deeper.

@ macroplay.Playpen.recursiveCanonicalName[Map[String,String]] 
res1: String = "scala.collection.immutable.Map[java.lang.String,java.lang.String]"


@ macroplay.Playpen.recursiveCanonicalName[Map[Seq[String],Seq[String]]] 
res3: String = "scala.collection.immutable.Map[scala.collection.immutable.Seq[scala.Predef.String],scala.collection.immutable.Seq[scala.Predef.String]]"

Any help (and your patience, scalameta makes me feel dumb) is greatly appreciated!

答案1

得分: 2

尝试按类型引用进行模式匹配

args.map(a =>
  a.asType match {
    case '[a] => recursiveCanonicalNameImpl[a].show.stripPrefix("\"").stripSuffix("\"")
  }
)

链接:

或者,您可以引入一个递归辅助函数来处理 TypeRepr 参数,而不是静态类型 T

def recursiveCanonicalNameImpl[T](using q: Quotes)(using tt: Type[T]): Expr[String] =
  import quotes.reflect.*

  def hlp(repr: TypeRepr): Expr[String] =
    repr.widenTermRefByName.dealias match
      case AppliedType(name, args) =>
        Expr(name.dealias.simplified.show + "[" + args.map(a =>
          hlp(a).show.stripPrefix("\"").stripSuffix("\"")
        ).mkString(",") + "]")
      case _ =>
        Expr(repr.dealias.simplified.show)

  val repr = TypeRepr.of[T]
  hlp(repr)
英文:

Try pattern matching by type quotation

args.map(a =>
  a.asType match {
    case '[a] => recursiveCanonicalNameImpl[a].show.stripPrefix("\"").stripSuffix("\"")
  }
)

https://stackoverflow.com/questions/73852787/tq-equivalent-in-scala-3-macros

https://stackoverflow.com/questions/68941796/explicit-type-conversion-in-scala-3-macros

https://stackoverflow.com/questions/70311751/what-scala-3-syntax-can-match-on-a-type-and-its-type-parameters-in-the-context-o

Alternatively you can introduce a recursive helper function for TypeRepr argument rather than static type T

def recursiveCanonicalNameImpl[T](using q: Quotes)(using tt: Type[T]): Expr[String] =
  import quotes.reflect.*

  def hlp(repr: TypeRepr): Expr[String] =
    repr.widenTermRefByName.dealias match
      case AppliedType(name, args) =>
        Expr(name.dealias.simplified.show + "[" + args.map(a =>
          hlp(a).show.stripPrefix("\"").stripSuffix("\"")
        ).mkString(",") + "]")
      case _ =>
        Expr(repr.dealias.simplified.show)

  val repr = TypeRepr.of[T]
  hlp(repr)

huangapple
  • 本文由 发表于 2023年1月9日 05:36:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/75051483.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定