3

scala マクロを使用して、指定された値で配列を埋める関数を作成しようとしています。たとえば、次の呼び出し:

val ary = Array( 0, 1, 2 )
fill3( ary, 50+25 )

次のように拡張する必要があります。

val ary = Array(0, 1, 2 )
{
  val $value = 50+25
  ary(0) = $value
  ary(1) = $value
  ary(2) = $value       
}

これが私の最初の試みです:

def fill3( ary: Array[Int], x: Int ) = macro fill_impl3

def fill_impl3( c: Context )
( ary: c.Expr[Array[Int]], x: c.Expr[Int]): c.Expr[Unit] = {
  import c.universe._        
  def const(x:Int) = Literal(Constant(x))

  //Precompute x
  val valName = newTermName("$value")
  val valdef = ValDef( Modifiers(), valName, TypeTree(typeOf[Int]), x.tree )

  val updates = List.tabulate( 3 ){
  i => Apply( Select( ary.tree, "update"), List( const(i), ??? ) )
  }

  val insts = valdef :: updates
  c.Expr[Unit](Block(insts:_*))
}

しかし、ここでは 2 つの理由で立ち往生しています。

  1. 事前計算された値を取得する方法がわからない ( $value)
  2. サイズ 3、4、6、9、および 27 の配列には、これらの関数がいくつか必要です。定義を乾燥させる方法はありますか、または、、、などと書く必要がfill3ありfill4ますfill6

続行する正しい方法はありますか?どうすれば私の2つの問題を解決できますか?

編集:コンパイル時にサイズを知る必要があるため、最初の質問が愚かであることに気付きました...

4

2 に答える 2

2
def fill(size:Int, ary: Array[Int], x: Int ) = macro fill_impl

def fill_impl( c: Context )
(size:c.Expr[Int], ary: c.Expr[Array[Int]], x: c.Expr[Int]): c.Expr[Unit] = {
  import c.universe._        
  def const(x:Int) = Literal(Constant(x))

  val Literal(Constant(arySize:Int)) = size.tree

  //Precompute x
  val valName = newTermName("$value")
  val valdef = ValDef( Modifiers(), valName, TypeTree(typeOf[Int]), x.tree )

  val updates = List.tabulate( arySize ){
  i => Apply( Select( ary.tree, "update"), List( const(i), Ident(valName) ) )
  }

  val insts = valdef :: updates
  c.Expr[Unit](Block(insts:_*))
}
于 2012-08-18T13:00:02.787 に答える
0

reify結果の生のツリーを印刷するとともに使用することで、それを理解しようとすることができます。

def fill_impl3( c: Context )
( ary: c.Expr[Array[Int]], x: c.Expr[Int]): c.Expr[Unit] = {
  import c.universe._
  val r = reify {
     val $value = x.splice
     val $arr  = ary.splice
     $arr(0)   = $value
     $arr(1)   = $value
     $arr(2)   = $value
  }
  println( showRaw( r.tree ))
  r
}

これは次のようなものを与えます

val vt = newTermName("$value")
val at = newTermName("$arr")
val ut = newTermName("update")
Block(List(
  ValDef(Modifiers(), vt, TypeTree(), ...),
  ValDef(Modifiers(), at, TypeTree(), ...),
  Apply(Select(Ident(at), ut), List(Literal(Constant(0)), Ident(vt))),
  Apply(Select(Ident(at), ut), List(Literal(Constant(1)), Ident(vt)))),
  Apply(Select(Ident(at), ut), List(Literal(Constant(2)), Ident(vt)))
)
于 2012-08-18T13:10:22.307 に答える