我将从一个例子开始.这里的List.fill元组与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!"
)
}
}
}
Run Code Online (Sandbox Code Playgroud)
我们可以使用以下方法:
scala> TupleExample.fill(3)("hello")
res0: (String, String, String) = (hello,hello,hello)
Run Code Online (Sandbox Code Playgroud)
这个家伙在几个方面都是一只奇怪的鸟.首先,arity参数必须是一个文字整数,因为我们需要在编译时使用它.在Scala的早期版本中,(根据我所知),方法甚至无法判断其中一个参数是否是编译时文字.
其次, …
当我使用支持类型级编程的库时,我经常会发现自己编写如下的注释(来自Paul Snively在Strange Loop 2012中提供的示例):
// But these invalid sequences don't compile:
// isValid(_3 :: _1 :: _5 :: _8 :: _8 :: _2 :: _8 :: _6 :: _5 :: HNil)
// isValid(_3 :: _4 :: _5 :: _8 :: _8 :: _2 :: _8 :: _6 :: HNil)
Run Code Online (Sandbox Code Playgroud)
/**
* If we wanted to confirm that the list uniquely contains `Foo` or any
* subtype of `Foo`, we could …Run Code Online (Sandbox Code Playgroud)