7

ここでは、Scala currying vs partially applied functionsを見ましたが、そこでは、カレンダー処理、部分的なアプリケーション、およびScalaの通常の関数の間の機能的および意味的な違いについての回答があります。スカラのカレイド、部分的に適用された機能、および「通常の」機能の間のパフォーマンス特性は何ですか?

我々はベースとして正常な機能のパフォーマンスを使用している場合は、私は、つまり...

機能に使用することができ、これらの異なる技術間のいずれかのパフォーマンスの考慮事項があるかどうかを学ぶことに興味がある:

def add3(a: Int, b: Int, c: Int) = a + b + c 
add3(1, 2, 3) 

そしてと比較:

// First 
(add3 _).curried(1)(2)(3) 

// Second 
val add2 = add3(1, _: Int, _: Int) 
val add1 = add2(2, _: Int) 
add1(3) 

// Third 
def add3(a: Int)(b: Int)(c: Int) = a + b + c 
add3(1)(2)(3) 

私はいくつかのパフォーマンスの低いコードを認識している場合、私はに留意することがあります物事は何ですか(スピードやメモリ使用量の点で)、私はこのコードセグメントで多くのカリングや部分的なアプリケーションが発生しているのを見ていますか?

ハスケルでは、私は、例えば、何個のサンクが生成されているのか見ているでしょう。私はScalaが部分的に適用され、カルト化された関数を渡すのに似たような方法を使用していると考えていましたが、Scalaがこれらのことを処理する方法の詳細は知っておく価値があります。

答えて

5

私は、javaにスニペットを変換するために、私のscala-to-java toolを使用し、ここでの結果は以下のとおりです。

def add3(a: Int, b: Int, c: Int) = a + b + c 
add3(1, 2, 3) 

結果:

  1. シンプルな関数呼び出しは、同様の機能呼び出しにtranspiledさ

    public final class _$$anon$1 { 
        private int add3(final int a, final int b, final int c) { 
         return a + b + c; 
        } 
    
        { 
         this.add3(1, 2, 3); 
        } 
    } 
    
  2. 「最初の」スニペット:(add3 _).curried(1)(2)(3)はtrです

    ((Function3<Integer, Object, Object, Object>)new _$$anon$1$$anonfun._$$anon$1$$anonfun$1(this)).curried().apply(BoxesRunTime.boxToInteger(1)).apply(BoxesRunTime.boxToInteger(2)).apply$mcII$sp(3); 
    

    私は定型書を省略しました。ここで起こるのは、ラッパー関数クラスがadd3の周りに作成され、そのクラスのメソッドcurriedが呼び出された場合、前のアプリケーションの結果でapplyが3回呼び出されます。 curriedhereのソースを確認することができます。それは、いくつかの高次関数(関数を返す関数)を返します。

    したがって、「case 0」と比較すると、シングルカリーコール用にいくつかの追加の関数ラッパーが作成されます。

  3. "セカンド":

    // Second 
    val add2 = add3(1, _: Int, _: Int) 
    val add1 = add2(2, _: Int) 
    add1(3) 
    

    私はtranspiled出力のページ全体を提供することはありません。必要に応じてhereを確認してください。基本的に何が起こるかは、add2add1の機能ラッパークラスは、対応する引数の数をとる単一のメソッドで生成されます。したがって、add1(3)に電話するとadd2が呼び出され、add3が呼び出されます。生成されたラッパーは実質的にシングルトンなので、オーバーヘッドはいくつかの関数呼び出しに限られています。第三に

  4. public final class _$$anon$1 { 
        private int add3(final int a, final int b, final int c) { 
         return a + b + c; 
        } 
    
        { 
         this.add3(1, 2, 3); 
        } 
    } 
    

    いますが、このval p = add3(1) _のように、例えば、カリー化方法でそれを使用しようとすると、機能的ラッパー:

    def add3(a: Int)(b: Int)(c: Int) = a + b + c 
    add3(1)(2)(3) 
    

    が再び単純な関数呼び出しにtranspiledされていますクラスが追加生成されます。

+0

私はこのことから集まることは、それはそれぞれの結果の機能を復帰させるためのシングルトンクラスを作成するため、カリー化と部分的にScalaで関数を適用するのオーバーヘッドは、ほとんど無視できるということです、量事実上の単純な関数呼び出しの大部分。 – josiah

関連する問題