2

別の式の奥深くからスカラー式に複数回アクセスするための最も簡潔でバイトコード効率の良い方法は何ですか?

次のコード(scalar4を除く)のすべての関数は、必要に応じて機能します。しかし、バイトコーダーだけが効率的なバイトコードを出力し(ISTORE 2 ILOAD 2でうまく終了しませんが)、他のバイトコーダーはそれぞれ5ダースのINVOKEを生成します。

このイディオムは、タプルの任意の部分をパラメーターとして渡す場合にも便利です。

for (a_tuple) { f(_._3, _._1) + g(_._2) }  // caution NOT legal Scala

この例では、イントロは1回だけ呼び出す必要がある高価な関数を表しています。

object Hack extends App
{
  @inline final def fur[T, V](x :T)(f :T => V) :V = f(x)

  @inline final def pfor[T, V](x :T)(pf :PartialFunction[T, V]) = pf(x)

  @inline final def cfor[T, V](x :T)(f :T => V) :V = x match { case x => f(x) }

  def intro :Int = 600 // only one chance to make a first impression

  def bytecoder = intro match { case __ => __ + __ / 600 }

  def functional = fur(intro) (x => x + x / 600)

  def partial = pfor(intro) { case __ => __ + __ / 600 }

  def cased = cfor(intro) ($ => $ + $ / 600)

  def optional = Some(intro).map(? => ? + ? / 600).get

  def folder = Some(intro).fold(0)(? => ? + ? / 600)

  // the for I wish for
  def scalar4 = for(intro) (_ + _ / 600) // single underline!

  println(bytecoder, functional, partial, cased, optional, folder)
}

public bytecoder()I

ALOAD 0
INVOKEVIRTUAL com/_601/hack/Hack$.intro ()I
ISTORE 1
ILOAD 1
ILOAD 1
SIPUSH 600
IDIV
IADD
ISTORE 2
ILOAD 2
IRETURN
4

2 に答える 2

2

一時的なvalを使用してローカルブロックを作成するだけです。真剣に。コンパクトです。「慣用的な」パイプよりもわずか1文字長くなります。

{ val x = whatever; x * x / 600 }
whatever match { case x => x * x / 600 }
whatever |> { x => x * x / 600 }

それは効率的です:可能な最小のバイトコード。

// def localval = { val x = whatever; x * x / 600 }
public int localval();
  Code:
   0:   aload_0
   1:   invokevirtual   #18; //Method whatever:()I
   4:   istore_1
   5:   iload_1
   6:   iload_1
   7:   imul
   8:   sipush  600
   11:  idiv
   12:  ireturn

それが行わない唯一のことは、接尾辞演算子として機能するmatchことです。そのフォームが本当に必要で、余分なバイトコードを許容できない場合は、そのために使用できます。

于 2013-02-28T23:20:11.780 に答える
1
// Canadian scalar "for" expression
@inline final case class four[T](x: T)
{
  @inline def apply(): T = x

  @inline def apply[V](f: Function1[T,          V]): V = f(x)
  @inline def apply[V](f: Function2[T, T,       V]): V = { val $ = x; f($, $) }
  @inline def apply[V](f: Function3[T, T, T,    V]): V = { val $ = x; f($, $, $) }
  @inline def apply[V](f: Function4[T, T, T, T, V]): V = { val $ = x; f($, $, $, $) }
  // ...
}

// Usage
val x = System.currentTimeMillis.toInt % 1 + 600

def a = four(x)() + 1
def b = four(x)(_ + 1)
def c = four(x)(_ + _ / x)
def d = four(x)(_ + _ / _)
def e = four(x)(_ + _ / _ - _) + 600

println(a, b, c, d, e)

これによりfour(){}、バイトコードとパフォーマンスが犠牲になり、スタイルが優先されます。

また、これは危険なほど伝統から外れており、下線はパラメータごとに1回だけ使用されます。

于 2013-03-10T12:47:08.177 に答える