我有一个表面上很简单的宏观问题,我已经用头撞了几个小时,但没有运气。也许有更多经验的人可以提供帮助。
我有以下宏:
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
object MacroObject {
def run(s: String): Unit =
macro runImpl
def runImpl(c: Context)(s: c.Tree): c.Tree = {
import c.universe._
println(s) // <-- I need the macro to know the value of s at compile time
q"()"
}
}
Run Code Online (Sandbox Code Playgroud)
问题是:我希望宏知道s传递给它的值——不是 AST s,而是s它本身的值。具体来说,我希望它具有这种行为:
def runTheMacro(str: String): Unit = MacroObject.run(str)
final val HardCodedString1 = "Hello, world!"
runTheMacro(HardCodedString1) // the macro should print "Hello, world!"
// to the console during macro expansion …Run Code Online (Sandbox Code Playgroud) 是否可以在 Dotty, Scala 3 中生成一个带有宏的新类?
兹拉亚
我正在将宏从 Scala 2 移植到 Scala 3。作为其工作的一部分,Scala 2 宏使用默认构造函数创建泛型类型的实例。在 Scala 2 中使用准引用很容易做到这一点,但我在 Scala 3 宏上遇到了困难。这是迄今为止我最好的方法:
import scala.quoted.*
inline def make[A <: AnyRef]: A = ${ makeThat[A] }
private def makeThat[A <: AnyRef : Type](using Quotes): Expr[A] =
import quotes.reflect.*
'{ new A().asInstanceOf[A] }
Run Code Online (Sandbox Code Playgroud)
如果没有.asInstanceOf[A],编译器会发出错误消息:
[error] -- [E007] Type Mismatch Error: ...
[error] 17 | '{ new A() }
[error] | ^^^^^^^
[error] |Found: Object
[error] |Required: A
[error] |
[error] |where: A is a type in method makeThat with …Run Code Online (Sandbox Code Playgroud) 我在 Scala 3 中定义了以下特征:
\ntrait A[T <: Tuple]\nRun Code Online (Sandbox Code Playgroud)\n然后,我使用 Scala 3 宏创建具有此特征的对象,对元组的实际类型执行进一步检查T;特别是,我想检查元组的所有类型(T_1,\xe2\x80\xa6,T_n)T是否是另一个给定类型的子类型B:
trait B\nprivate def allSubtypesOfB[T <: Tuple: Type](using quotes: Quotes): Boolean = {\n import quotes.reflect.*\n case '[Nothing] => false // I don't want nothing to be in T\n case '[head *: tail] if TypeRepr.of[head] <:< TypeRepr.of[B] => allSubtypesOfB[tail]\n case '[EmptyTuple] => true\n case _ => false\n}\n\ninline def createA[T <: Tuple] = ${ createAImpl[T] }\nprivate def createAImpl[T …Run Code Online (Sandbox Code Playgroud) 有没有办法使用scala-macros获取给定构造函数的参数名称?
谢谢
在回答这个问题时,我一直在使用宏天堂分支在Scala中实现Haskell风格的"where"表达式.代码可在scala-where处获得.我现在可以写下面的内容:
val result = where ( f1(1) * f2(2), {
def f1(x : Int) = x + 1
def f2(x : Int) = x + 2
})
Run Code Online (Sandbox Code Playgroud)
但是,我真正想做的是能够在中缀位置调用它:
val result = ( f1(1) * f2(2)) where {
def f1(x : Int) = x + 1
def f2(x : Int) = x + 2
}
Run Code Online (Sandbox Code Playgroud)
通常情况下,这种事情很容易,但我看不到如何使用宏调用.表达式(f1(1)*f2(2))将不会在宏应用程序之前键入,因此构建隐式值类的操作不起作用.有没有办法获得这种语法呢?
如果做不到这一点,只需要两个参数列表即可:
val result = where (f1(1) * f2(2)) {
def f1(x : Int) = x + 1
def f2(x : Int) …Run Code Online (Sandbox Code Playgroud) 例如,要获取宏的呼叫站点上的所有值及其类型?或者至少只是当前班级的价值?例如:
class A {
val v1 = 10
var v2 = "2"
def m {
val m3 = true
// Here I would like to get information that v1: Int, v2: String and
// v3: Boolean are available
macroInvocation()
}
}
Run Code Online (Sandbox Code Playgroud)
我查看了Context和Universe,但找不到好的方法.
到目前为止我找到的唯一解决方案是获取宏的封闭类/方法(通过Context),并搜索树.
我的WeakTypeTag宏中有一些类型,我想生成如下代码:
macroCreate[SomeObject] // => SomeObject(1)
Run Code Online (Sandbox Code Playgroud)
宏的定义将是这样的:
def macroCreate[A] = macro _macroCreate[A]
def _macroCreate[A](c: Context)(implicit wtt: c.WeakTypeTag[A]) = {
c.Expr(Apply(Select(???, newTermName("apply")), List(c.literal(1).tree)))
}
Run Code Online (Sandbox Code Playgroud)
问题是,我如何得到Select给定的类型?
我可以使用一种解决方法,将类型转换为字符串,拆分"."然后创建一个Select字符串列表,但这看起来很糟糕.
是否可以Select直接从类型标签创建?
如果可能的话,如何使用反射和宏列出所有可见的含义?我需要这个能够分析可用的类型类实例.
case class Artist (name: String, genres: Set[Genre])
case class Genre (name: String)
object CatalogueDB extends MySQL {
implicit val artistEntity = new Entity[Artist] {...}
implicit val genreEntity = new Entity[Genre] {...}
}
trait MySQL {
// Typeclasses let me restrict methods on `MySQL` to work only for types,
// which are associated with its instance.
// E.g., the following method will only compile when either an `Artist` or
// a `Genre` is passed to it when called on …Run Code Online (Sandbox Code Playgroud) 我正在写一个SBT插件.我想使用Circe JSON库,但它需要Scala 2.10上的Macro Paradise编译器插件.
通常,您将编译器插件添加到build.sbtSBT插件project/plugins.sbt.
现在,当您构建SBT插件时,其他插件将成为依赖项,因此您将它们放入并将build.sbt它们传播到您使用SBT插件的项目.
当我将以下片段放入build.sbt我的SBT插件时:
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)
Run Code Online (Sandbox Code Playgroud)
Paradise编译器插件是否会传播到下游项目?
scala ×10
scala-macros ×10
macros ×5
reflection ×2
scala-2.10 ×2
scala-3 ×2
annotations ×1
constructor ×1
dotty ×1
generics ×1
sbt ×1
sbt-plugin ×1
tuples ×1