有没有办法在模式匹配中使用宏的参数?我想这样做:
def extr(X:AnyRef) = macro extrImpl
def extrImpl(c:Context)(X:c.Expr[AnyRef]):c.Expr[AnyRef] = {
import c.universe._
val tree = reify {
new {
def unapply(x:String):Option[String] = x match {
case X.splice => Some(x) //error
case _ => None
}
}
}.tree
c.Expr(c.typeCheck(tree))
}
Run Code Online (Sandbox Code Playgroud)
但不幸的是编译器说"需要稳定的标识符,但X.splice发现了".通常,人们可以通过首先分配val来解决这个问题,例如:
val XX = X.splice
Run Code Online (Sandbox Code Playgroud)
但当然,这也不适用于拼接.
给出如下内容:
class A {
def f(x: X) = ...
def g(y: Y, z: Z) = ...
...
}
Run Code Online (Sandbox Code Playgroud)
如何(自动)提取功能:
object A {
val f' = (a: A, x: X) => a.f(x) // do this automagically for any arbitrary f
val g' = (a: A, y: Y, z: Z) => a.g(y, z) // and deal with arity > 1 too
...
}
Run Code Online (Sandbox Code Playgroud)
使用此精确类型签名(首先是对象,然后是参数列表).让我非常清楚地说明问题:
"给定的方法
f(x1: X1, ..., xn: Xn)中的一类的上下文中定义A,如何自动提取功能f'的是(ⅰ) 接收一个实例a类型的A …
我想将静态字段(bar在此示例中命名Foo)添加到具有类型宏(命名Static)的类(已命名).
这就是我目前正在尝试这样做的方式:
宏
import language.experimental.macros
import scala.reflect.macros.Context
package object statics {
type Static = macro Statics.addStaticField
object Statics {
def addStaticField(c: Context): c.Tree = {
import c.universe._
val STATIC = 1 << 23
type CompilerSymbol = scala.tools.nsc.Global#Symbol
def setFlag(symbol: Symbol, flag: Long) {
val compilerSymbol = symbol.asInstanceOf[CompilerSymbol]
println("Setting flag ...")
compilerSymbol.setFlag(flag)
}
def printFlags(symbol: Symbol) {
println("Flags: " + symbol.asInstanceOf[CompilerSymbol].flagString)
}
val staticField: ValDef =
ValDef(
mods = Modifiers(),
name = TermName("bar"),
tpt = …Run Code Online (Sandbox Code Playgroud) 我正在尝试确定在编译时传递给宏的参数的类型.它似乎在我使用<:<时起作用,但在我使用时不起作用=:=.我不知道为什么.谁能指出我正确的方向?我在下面列出了示例代码.
这个宏:
import language.experimental.macros
import scala.reflect.macros.Context
object Macros {
def say(param: Any): Unit = macro impl
def impl(c: Context)(param: c.Expr[Any]): c.Expr[Unit] = {
if (param.actualType.<:<(c.universe.typeOf[String])) {
c.universe.reify { printf("string: %s\n", param.splice) }
} else if (param.actualType.<:<(c.universe.typeOf[Int])) {
c.universe.reify { printf("int: %d\n", param.splice) }
} else {
c.universe.reify { printf("any: %s\n", param.splice) }
}
}
}
Run Code Online (Sandbox Code Playgroud)
由此代码调用:
object Test extends App {
Macros.say("Hi")
Macros.say(1)
Macros.say(Blah)
}
case object Blah
Run Code Online (Sandbox Code Playgroud)
返回:
string: Hi
int: 1
any: Blah
Run Code Online (Sandbox Code Playgroud)
但是,如果我检查类型equality( …
假设我有一个包含三个子项目的Scala项目,文件如下:
foo/src/main/scala/Foo.scala
foo/src/main/resources/foo.txt
bar/src/main/scala/Bar.scala
bar/src/main/resources/bar.txt
baz/src/main/scala/Baz.scala
baz/src/main/resources/baz.txt
Run Code Online (Sandbox Code Playgroud)
Foo.scala 包含一个读取给定路径资源的简单宏:
import scala.language.experimental.macros
import scala.reflect.macros.Context
object Foo {
def countLines(path: String): Option[Int] = macro countLines_impl
def countLines_impl(c: Context)(path: c.Expr[String]) = {
import c.universe._
path.tree match {
case Literal(Constant(s: String)) => Option(
this.getClass.getResourceAsStream(s)
).fold(reify(None: Option[Int])) { stream =>
val count = c.literal(io.Source.fromInputStream(stream).getLines.size)
reify(Some(count.splice))
}
case _ => c.abort(c.enclosingPosition, "Need a literal path!")
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果资源可以打开,则countLines返回行数; 否则它是空的.
另外两个Scala源文件只调用此宏:
object Bar extends App {
println(Foo.countLines("/foo.txt"))
println(Foo.countLines("/bar.txt"))
println(Foo.countLines("/baz.txt"))
}
Run Code Online (Sandbox Code Playgroud)
和:
object Baz extends …Run Code Online (Sandbox Code Playgroud) 更新:我怀疑什么,我想也许是不可能的,我已经写了一篇博客文章与我的推理(和一些替代品)在这里.我很高兴被告知我错了.
假设我想使用带有宏实现的工厂方法创建特征实例.此方法将参数作为资源的路径,宏将读取并在编译时将其解析为从字符串到字符串的映射.
那部分都相当简单.现在假设我想将结果映射与我正在创建的实例相关联,以便我可以在涉及该实例的后续宏调用中使用它.
我至关重要的是不希望地图成为实例的成员,或者在运行时以任何形式存在.我也不想多次解析同一个资源.这是我想要的那种东西的草图:
import scala.language.experimental.macros
import scala.reflect.macros.Context
trait Foo {
def lookup(key: String): String = macro Foo.lookup_impl
}
object Foo {
def parseResource(path: String): Map[String, String] = ???
def apply(path: String): Foo = macro apply_impl
def apply_impl(c: Context)(path: c.Expr[String]): c.Expr[Foo] = {
import c.universe._
val m = path.tree match {
case Literal(Constant(s: String)) => parseResource(s)
}
val tree = reify(new Foo {}).tree
// Somehow associate the map with this tree here.
c.Expr(tree)
}
def …Run Code Online (Sandbox Code Playgroud) 我有以下代码:
object Test extends App {
import Macros._
val f = 1
Macros.get(f)
}
Run Code Online (Sandbox Code Playgroud)
import language.experimental.macros
import scala.reflect.macros.Context
object Macros {
def get(a: Int) = macro getImpl
def getImpl(c: Context)(a: c.Expr[Int]) = {
import c.universe._
println(showRaw(a))
}
}
Run Code Online (Sandbox Code Playgroud)
它返回:
Expr(Select(This(newTypeName("Test")), newTermName("f")))
如何从termName("f")一个1值中提取?有可能用宏吗?
我敢肯定,有一种更优雅的方式来编写以下宏,该宏将打印变量的名称和值:
def mprintx(c: Context)(linecode: c.Expr[Any]): c.Expr[Unit] = {
import c.universe._
val namez = (c.enclosingImpl match {
case ClassDef(mods, name, tparams, impl) =>
c.universe.reify(c.literal(name.toString).splice)
case ModuleDef(mods, name, impl) =>
c.universe.reify(c.literal(name.toString).splice)
case _ => c.abort(c.enclosingPosition, "NoEnclosingClass")
}).toString match {
case r_name(n) => n
case _ => "Unknown?"
}
val msg = linecode.tree.productIterator.toList.last.toString.replaceAll("scala.*\\]", "").replaceAll(namez+"\\.this\\.", "").replaceAll("List", "")
reify(myPrintDln(c.Expr[String](Literal(Constant(msg))).splice+" ---> "+linecode.splice))
}
def myPrintIt(linecode: Any) = macro mprintx
Run Code Online (Sandbox Code Playgroud)
由以下程序调用:
object Zabi2 extends App {
val l = "zab"
val kol = 345
var zub = …Run Code Online (Sandbox Code Playgroud) 我想做这样的事情:
def assuming[A](condition: => Boolean)(f: => A): A = {
require(condition, /* print source-code of condition */)
f
}
Run Code Online (Sandbox Code Playgroud)
样品用法:
def fib(n: Int) = n match { // yes, yes, I know this is not efficient
case 0 => 0
case 1 => 1
case i => assuming(i > 0) { fib(i-1) + fib(i-2) }
}
Run Code Online (Sandbox Code Playgroud)
现在,例如,如果你调用fib(-20),我希望它抛出一个带有Assertion failed: -20 > 0或的消息的异常Assertation failed: i > 0
scala scala-2.10 scala-macros scala-2.11 scala-macro-paradise
我有一个多项目包含一个私有宏子项目,其用途仅限于实现其他子项目的方法体.也不应该在其他子项目的运行时类路径上,也不应该在其他子项目的已发布POM中以任何形式显示.因此,其他sbt项目可以在不知道宏子项目的情况下使用此项目中的库.
对于外部依赖,我发现这个SO Q&A工作得很好,但对于子项目,当我尝试做类似的事情时dependsOn,sbt抱怨配置"compileonly"找不到.
ivyConfigurations += config("compileonly").hide
val macro = Project("macro", file("macro"))
val lib = Project("lib", file("lib")).dependsOn(macro % "compile->compileonly")
Run Code Online (Sandbox Code Playgroud) scala-macros ×10
scala ×9
macros ×3
sbt ×2
scala-2.10 ×2
classpath ×1
maven ×1
oop ×1
reflection ×1
scala-2.11 ×1
static ×1