部分的な機能を持つScalaマクロを実装し、その関数のパターンをいくつか変換して、与えられた式に適用します。私は、一部の機能を分解applyOrElse機能の症例定義を選択し、それぞれの定義に必要な変換を実行し、戻って一緒にすべてをかけるScalaマクロを使用して部分関数を変換して適用する方法は?
def myMatchImpl[A: c.WeakTypeTag, B: c.WeakTypeTag](c: Context)(expr: c.Expr[A])(patterns: c.Expr[PartialFunction[A, B]]): c.Expr[B] = {
import c.universe._
/*
* Deconstruct the partial function and select the relevant case definitions.
*
* A partial, anonymus function will be translated into a new class of the following form:
*
* { @SerialVersionUID(0) final <synthetic> class $anonfun extends scala.runtime.AbstractPartialFunction[A,B] with Serializable {
*
* def <init>(): anonymous class $anonfun = ...
*
* final override def applyOrElse[...](x1: ..., default: ...): ... = ... match {
* case ... => ...
* case (defaultCase$ @ _) => default.apply(x1)
* }
*
* def isDefined ...
* }
* new $anonfun()
* }: PartialFunction[A,B]
*
*/
val Typed(Block(List(ClassDef(a, b, x, Template(d, e, List(f, DefDef(g, h, i, j, k, Match(l, allCaseDefs)), m)))), n), o) = patterns.tree
/* Perform transformation on all cases */
val transformedCaseDefs: List[CaseDef] = allCaseDefs map {
case caseDef => caseDef // This code will perform the desired transformations, now it's just identity
}
/* Construct anonymus partial function with transformed case patterns */
val result = Typed(Block(List(ClassDef(a, b, x, Template(d, e, List(f, DefDef(g, h, i, j, k, Match(l, transformedCaseDefs)), m)))), n), o)
// println(show(result))
c.Expr[B](q"$result($expr)")
}
:そうするには
は、私は次のコードで開始しました。マクロは次のように呼び出されます。
def myMatch[A, B](expr: A)(patterns: PartialFunction[A, B]): B = macro myMatchImpl[A,B]
残念ながら、これは期待どおりに動作しません。
object creation impossible, since method isDefinedAt in trait PartialFunction of type (x: Option[Int])Boolean is not defined
生成された部分関数収率をどの明確
({
final <synthetic> class $anonfun extends scala.runtime.AbstractPartialFunction[Option[Int],Int] with Serializable {
def <init>(): anonymous class $anonfun = {
$anonfun.super.<init>();
()
};
final override def applyOrElse[A1 <: Option[Int], B1 >: Int](x2: A1, default: A1 => B1): B1 = ((x2.asInstanceOf[Option[Int]]: Option[Int]): Option[Int] @unchecked) match {
case (x: Int)Some[Int]((n @ _)) => n
case scala.None => 0
};
final def isDefinedAt(x2: Option[Int]): Boolean = ((x2.asInstanceOf[Option[Int]]: Option[Int]): Option[Int] @unchecked) match {
case (x: Int)Some[Int]((n @ _)) => true
case scala.None => true
case (defaultCase$ @ _) => false
}
};
new $anonfun()
}: PartialFunction[Option[Int],Int])
を印刷するので、これは、少し混乱して次のエラーメッセージで
def test(x: Option[Int]) = myMatch(x){
case Some(n) => n
case None => 0
}
結果は単純な例ではマクロを使用してisDefinedAtメソッドを定義します。
誰もがアイデアを持っていますが、何が問題なのですか、これをどうやって行うのですか?
import scala.language.experimental.macros
import scala.reflect.macros.Context
def myMatchImpl[A: c.WeakTypeTag, B: c.WeakTypeTag](c: Context)(
expr: c.Expr[A]
)(
patterns: c.Expr[PartialFunction[A, B]]
): c.Expr[B] = {
import c.universe._
val transformer = new Transformer {
override def transformCaseDefs(trees: List[CaseDef]) = trees.map {
case caseDef => caseDef
}
}
c.Expr[B](q"${transformer.transform(patterns.tree)}($expr)")
}
def myMatch[A, B](expr: A)(patterns: PartialFunction[A, B]): B =
macro myMatchImpl[A,B]
def test(x: Option[Int]) = myMatch(x) {
case Some(n) => n
case None => 0
}
あなたは変換が唯一の場合に適用されていることを確認するために、いくつかの追加の機械が必要になる場合があります
は
質問の中で最も興味深い部分は答えではありませんが、['Transformer'](http://www.scala-lang.org/api/current/index.html#scala.reflect .api.Trees $ Transformer)?それはおそらくより頑強に(あなたが望むように)(https://gist.github.com/travisbrown/6340753)するべきです。 –
@TravisBrown Transformerクラスはまさに私が探していたものです。ヒントありがとうございます。あなたの要点を答えとして投稿してください。 –