英文:
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("\"")
}
)
链接:
- stackoverflow.com/questions/73852787/tq-equivalent-in-scala-3-macros
- stackoverflow.com/questions/68941796/explicit-type-conversion-in-scala-3-macros
- stackoverflow.com/questions/70311751/what-scala-3-syntax-can-match-on-a-type-and-its-type-parameters-in-the-context-o
或者,您可以引入一个递归辅助函数来处理 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
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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论