标签: scala-macros

如何使用Scala宏在方法调用中为命名参数建模?

在某些用例中,创建对象的副本很有用,该对象是一组案例类的案例类的实例,它们具有共同的特定值.

例如,让我们考虑以下案例类:

case class Foo(id: Option[Int])
case class Bar(arg0: String, id: Option[Int])
case class Baz(arg0: Int, id: Option[Int], arg2: String)
Run Code Online (Sandbox Code Playgroud)

然后copy可以在每个案例类实例上调用:

val newId = Some(1)

Foo(None).copy(id = newId)
Bar("bar", None).copy(id = newId)
Baz(42, None, "baz").copy(id = newId)
Run Code Online (Sandbox Code Playgroud)

如此此处所述,没有简单的方法来像这样抽象:

type Copyable[T] = { def copy(id: Option[Int]): T }

// THIS DOES *NOT* WORK FOR CASE CLASSES
def withId[T <: Copyable[T]](obj: T, newId: Option[Int]): T =
  obj.copy(id = newId)
Run Code Online (Sandbox Code Playgroud)

所以我创建了一个scala宏,它完成了这项工作(几乎):

import scala.reflect.macros.Context

object Entity {

  import …
Run Code Online (Sandbox Code Playgroud)

scala scala-macros

23
推荐指数
1
解决办法
3318
查看次数

尝试使用Shapeless递归地将case类转换为异类列表的奇怪行为

我昨晚熬夜试图弄清楚这个无形的问题,如果我不把它从胸前拿走,我担心它会吃掉我的晚上,所以这里就是这样.

在这个最小化版本中,我只是定义了一个类型类,它将递归转换为异构列表:

import shapeless._

trait DeepHLister[R <: HList] extends DepFn1[R] { type Out <: HList }

trait LowPriorityDeepHLister {
  type Aux[R <: HList, Out0 <: HList] = DeepHLister[R] { type Out = Out0 }

  implicit def headNotCaseClassDeepHLister[H, T <: HList](implicit
    dht: DeepHLister[T]
  ): Aux[H :: T, H :: dht.Out] = new DeepHLister[H :: T] {
    type Out = H :: dht.Out
    def apply(r: H :: T) = r.head :: dht(r.tail)
  }
}

object DeepHLister extends LowPriorityDeepHLister {
  implicit …
Run Code Online (Sandbox Code Playgroud)

scala shapeless scala-macros

21
推荐指数
2
解决办法
1208
查看次数

Scala宏:typed(又名typechecked)和无类型树之间有什么区别

我开始使用scala宏,它们很棒,但我遇到了typed(又是typechecked)和无类型Trees 之间的区别.

例如,c.eval由于某种原因,您无法使用类型检查的树进行调用.我在scala宏文档中找不到关于这个'typechecked'的文档(我知道他们仍然在努力,这可能是某些事情需要在某天添加).

对于一个Tree被类型检查来说意味着什么?为什么它们如此不同以至于显然c.eval无法处理类型检测Tree(反之则对我更有意义).

我想这可能是编译器101,但我没有采取这个过程:(任何解释或指向文章/文件的指针将不胜感激!

scala typechecking scala-macros

15
推荐指数
1
解决办法
1428
查看次数

"动态"使用宏创建案例类

我想创建一个密封的抽象和案例类的宏生成层次结构.有一个与http://docs.scala-lang.org/overviews/macros/typemacros.html类似的例子,但现在已经过时了.这还有可能吗?

我认为为某些指定的语法生成类型安全的AST会非常强大.理想情况下,IDE可以解析所有类.

scala case-class scala-macros

14
推荐指数
1
解决办法
6810
查看次数

获取密封特征的子类

是否有可能(通过宏,某种形式的无形自动或其他形式)获得密封特征的子类列表:

  • 在编译时?
  • 在运行时?

scala shapeless scala-macros scala-reflect

14
推荐指数
1
解决办法
4459
查看次数

为什么运行时反射Universe和宏Universe为scala.None创建了两个不同的树?

如果我有一个宏tranforms代码如下:

  (src: a.b.c.TestEntity) =>
    {
      z.y.TestTable(None)
    }
Run Code Online (Sandbox Code Playgroud)

要匹配该AST的None部分,我可以使用提取器,例如:

  object NoneExtractor {
    def unapply(t: Tree): Boolean = t match {
      case Select(Ident(scala), none) if scala.encoded == "scala" && none.encoded == "None" => true
      case _ => false
    }
  }
Run Code Online (Sandbox Code Playgroud)

因为showRawAST的None部分看起来像:

Select(Ident(scala), None)
Run Code Online (Sandbox Code Playgroud)

然而,如果我想编写单元测试,NoneExtractor我不想编译和重建宏,并在宏编译的项目中托管测试.我想在宏的项目中对提取器进行单元测试,这表明运行时反射是可行的方法:

val t = reify {

  (src: a.b.c.TestEntity) =>
    {
      z.y.TestTable(None)
    }

}.tree 
Run Code Online (Sandbox Code Playgroud)

然而树是完全不同的,在showRaw那棵树中看起来像是:

Ident(scala.None)
Run Code Online (Sandbox Code Playgroud)

这对于编写负面测试和检查宏的错误处理来说是个坏消息.您不能使用来自另一个项目的宏为宏编写负面测试,因为代码无法编译(并且您无法使用编译错误调试负面测试).

为什么在编译时反射和运行时反射之间,像None一样基本的表示形式如此不同?有没有办法在宏项目中创建可测试的树片段,这与在编译时反射期间传递给宏的AST相同?

scala scala-macros

13
推荐指数
1
解决办法
241
查看次数

如何在reify子句中使用Scala宏中计算的类型?

我一直在使用Scala Macros并在宏中使用以下代码:

    val fieldMemberType = fieldMember.typeSignatureIn(objectType) match {
      case NullaryMethodType(tpe)   => tpe
      case _                      => doesntCompile(s"$propertyName isn't a field, it must be another thing")
    }

    reify{
      new TypeBuilder() {
        type fieldType = fieldMemberType.type
      }
    }
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,我已经成功了c.universe.Type fieldMemberType.这表示对象中某个字段的类型.一旦我得到了,我想TypeBuilder在reify中创建一个新对象.TypeBuilder是一个带抽象参数的抽象类.这个抽象参数是fieldType.我希望这fieldType是我之前找到的类型.

运行此处显示的代码会返回一个fieldMemberType not found.有什么方法可以让我fieldMemberType在reify子句中工作吗?

scala scala-2.10 scala-macros

12
推荐指数
2
解决办法
3373
查看次数

Introspect参数传递给Scala宏

我想编写一个Scala宏,它将一个case类的实例作为参数.可以传递给宏的所有对象都必须实现特定的标记特征.

以下代码段显示了标记特征和实现它的两个示例案例类:

trait Domain
case class Country( id: String, name: String ) extends Domain
case class Town( id: String, longitude: Double, latitude: Double ) extends Domain
Run Code Online (Sandbox Code Playgroud)

现在,我想使用宏编写以下代码,以避免运行时反射的严重性及其线程不安全:

object Test extends App {

  // instantiate example domain object
  val myCountry = Country( "CH", "Switzerland" )

  // this is a macro call
  logDomain( myCountry )
} 
Run Code Online (Sandbox Code Playgroud)

logDomain在不同的项目中实现,看起来类似于:

object Macros {
  def logDomain( domain: Domain ): Unit = macro logDomainMacroImpl

  def logDomainMacroImpl( c: Context )( domain: c.Expr[Domain] ): c.Expr[Unit] = { …
Run Code Online (Sandbox Code Playgroud)

macros scala scala-macros

12
推荐指数
2
解决办法
1388
查看次数

无法在Macro生成的类中访问方法

我有以下宏定义一个类并返回该类的实例(使用Scala 2.10.2和宏插件):

def test[T] = macro testImpl[T]

def testImpl[T : c.WeakTypeTag](c: Context): c.Expr[Any] = {
  import c.universe._
  val className = newTypeName("Test")

  c.Expr { q"""
    class $className  {
      def method = 1
    }
    new $className
  """}
}
Run Code Online (Sandbox Code Playgroud)

当我调用宏时:

case class Cat(name: String)

val t = test[Cat].method
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

method method in class Test cannot be accessed in Test
val t = test[Cat].method
                   ^
Run Code Online (Sandbox Code Playgroud)

我的总体目标是使用吸血鬼方法并使用准引号来描述生成的类.我该如何解决这个错误?

macros scala scala-macros

12
推荐指数
1
解决办法
1222
查看次数

在Maven项目中启用宏天堂Scala编译器插件

我只是通过将scala-reflect.jar库作为pom中的依赖项包含普通scala-2.10宏在maven项目中工作,但是我需要打开宏天堂呢?我使用的是scala-2.10和scala-maven-plugin-3.1.5.

scala maven scala-2.10 scala-maven-plugin scala-macros

12
推荐指数
1
解决办法
3395
查看次数