web-dev-qa-db-ja.com

Java 8で2つの矢印のあるラムダは何を意味しますか?

以前にいくつかのJava 8つのチュートリアルを読んだことがあります。

今、私は次のトピックに遭遇しました: Does Java support Currying?

ここで、次のコードが表示されます。

IntFunction<IntUnaryOperator> curriedAdd = a -> b -> a + b;
System.out.println(curriedAdd.apply(1).applyAsInt(12));

この例では2つの要素を合計することを理解していますが、構成を理解できません。

a -> b -> a + b;

式の左部分に従って、この行は次の機能を実装する必要があります。

R apply(int value); 

この前に、私は1つの矢印でのみラムダに会った。

117
gstackoverflow

これを短縮形ではないラムダ構文またはプレラムダJava無名クラス構文として表現すると、何が起こっているかがより明確になります...

元の質問。なぜ2つの矢印なのですか?単純な、定義されている2つの関数があります...最初の関数は関数定義関数であり、2番目はその関数の結果です。それぞれに定義するには、->演算子が必要です。

非速記

IntFunction<IntUnaryOperator> curriedAdd = (a) -> {
    return (b) -> {
        return a + b;
    };
};

事前ラムダJava 8

IntFunction<IntUnaryOperator> curriedAdd = new IntFunction<IntUnaryOperator>() {
    @Override
    public IntUnaryOperator apply(final int value) {
        IntUnaryOperator op = new IntUnaryOperator() {
            @Override
            public int applyAsInt(int operand) {
                return operand + value;
            }
        };
        return op;
    }
};
118
Adam

IntFunction<R>は関数int -> RIntUnaryOperatorは関数int -> int

したがって、IntFunction<IntUnaryOperator>は、intをパラメーターとして受け取り、intをパラメーターとして受け取り、intを返す関数です。

a -> b -> a + b;
^    |         |
|     ---------
|         ^
|         |
|         The IntUnaryOperator (that takes an int, b) and return an int (the sum of a and b)
|
The parameter you give to the IntFunction

匿名クラスを使用してラムダを「分解」すると、より明確になる可能性があります。

IntFunction<IntUnaryOperator> add = new IntFunction<IntUnaryOperator>() {
    @Override
    public IntUnaryOperator apply(int a) {
        return new IntUnaryOperator() {
            @Override
            public int applyAsInt(int b) {
                return a + b;
            }
        };
    }
};
48
Alexis C.

括弧を追加すると、これがより明確になる場合があります。

IntFunction<IntUnaryOperator> curriedAdd = a -> (b -> (a + b));

または、おそらく中間変数が役立つ場合があります。

IntFunction<IntUnaryOperator> curriedAdd = a -> {
    IntUnaryOperator op = b -> a + b;
    return op;
};
29
Tagir Valeev

より明確にするために、そのラムダ式を括弧で書き直しましょう:

IntFunction<IntUnaryOperator> curriedAdd = a -> (b -> (a + b));

したがって、intを返すFunctionを取る関数を宣言しています。より具体的には、返される関数はintを取り、int(2つの要素の合計)を返します。これは IntUnaryOperator として表すことができます=。

したがって、curriedAddintを取り、IntUnaryOperatorを返す関数であるため、 IntFunction<IntUnaryOperator>

23
Tunaki

2つのラムダ式です。

IntFunction<IntUnaryOperator> curriedAdd = 
  a -> { //this is for the fixed value
    return b -> { //this is for the add operation
      return a + b;
    };
  }

IntUnaryOperator addTwo = curriedAdd.apply(2);
System.out.println(addTwo.applyAsInt(12)); //prints 14
9
a better oliver

IntFunction を見ると、より明確になるかもしれません:_IntFunction<R>_はFunctionalInterfaceです。 intを取り、タイプRの値を返す関数を表します。

この場合、戻り型RFunctionalInterface、つまりIntUnaryOperatorです。したがって、first(外部)関数自体が関数を返します。

この場合:intに適用されると、curriedAddintを再びとる関数を返すことになっています(そして再びintを返します。 IntUnaryOperatorは何をしますか)。

関数型プログラミングでは、関数の型を_param -> return_value_として記述するのが一般的であり、ここで正確に確認できます。したがって、curriedAddのタイプは_int -> int -> int_(または、それがよければ、int -> (int -> int))です。

Java 8のラムダ構文はこれに沿っています。このような関数を定義するには、次のように記述します

_a -> b -> a + b
_

これは実際のラムダ計算と非常によく似ています:

_λa λb a + b
_

_λb a + b_は、単一のパラメーターbを取り、値(合計)を返す関数です。 _λa λb a + b_は、単一のパラメーターaを受け入れ、単一のパラメーターの別の関数を返す関数です。 _λa λb a + b_は、aがパラメーター値に設定された_λb a + b_を返します。

8
dhke