2012-12-12 43 views
72

我将从一个例子开始。下面是List.fill元组等效为斯卡拉2.10宏:记录Scala 2.10宏

import scala.language.experimental.macros 
import scala.reflect.macros.Context 

object TupleExample { 
    def fill[A](arity: Int)(a: A): Product = macro fill_impl[A] 

    def fill_impl[A](c: Context)(arity: c.Expr[Int])(a: c.Expr[A]) = { 
    import c.universe._ 

    arity.tree match { 
     case Literal(Constant(n: Int)) if n < 23 => c.Expr(
     Apply(
      Select(Ident("Tuple" + n.toString), "apply"), 
      List.fill(n)(a.tree) 
     ) 
    ) 
     case _ => c.abort(
     c.enclosingPosition, 
     "Desired arity must be a compile-time constant less than 23!" 
    ) 
    } 
    } 
} 

我们可以按如下方式使用此方法:

scala> TupleExample.fill(3)("hello") 
res0: (String, String, String) = (hello,hello,hello) 

这家伙是几个方面的一个奇怪的鸟。首先,arity参数必须是一个字面整数,因为我们需要在编译时使用它。在以前的Scala版本中,对于一个方法来说,没有办法(据我所知)甚至不知道它的一个参数是否是编译时的文字。

二,Product返回类型is a lie - 静态返回类型将包含由参数确定的特定元素和元素类型,如上所示。

那么我会如何记录这件事?在这一点上我并不期待Scaladoc的支持,但我希望有一种习惯或最佳实践(不仅仅是确保编译时错误消息是清晰的),这会使其运行到宏观方法中 - 潜在的离奇要求 - 对于Scala 2.10库的用户来说不会那么令人惊讶。

新的宏系统(例如,ScalaMock,Slick,其他列出的here)的最成熟的演示在方法级别上仍然是相对未记录的。任何示例或指针都会受到赞赏,包括来自其他语言的具有类似宏观系统的示例或指针。

+12

关于ScalaMock,作为作者,我非常感谢关于如何改进文档的建议。 ScalaMock实际上是一个DSL,因此记录单个方法并不一定意味着太多。我试图在这里整体记录DSL:http://scalamock.org/api/index.html#org.scalamock.package,这里有入门文档:http://www.paulbutcher.com/2012/10/scalamock3-step-by-step /我可以添加哪些帮助? –

+2

@PaulButcher:我不是故意批评ScalaMock,而是编辑了更清晰的答案。我发现读取代码非常有用,因为我一直在试图理解Scala的宏,我认为高级文档非常清晰。 –

+8

没有冒犯。但是,我肯定会感谢任何和所有我可以改进的方法。 –

回答

1

我认为记录这些文件的最好方法是使用示例代码,因为迈尔斯在他的无形的实验macro based branch中已经做了。