以前にいくつかの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つの矢印でのみラムダに会った。
これを短縮形ではないラムダ構文またはプレラムダJava無名クラス構文として表現すると、何が起こっているかがより明確になります...
元の質問。なぜ2つの矢印なのですか?単純な、定義されている2つの関数があります...最初の関数は関数定義関数であり、2番目はその関数の結果です。それぞれに定義するには、->
演算子が必要です。
IntFunction<IntUnaryOperator> curriedAdd = (a) -> {
return (b) -> {
return a + b;
};
};
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;
}
};
IntFunction<R>
は関数int -> R
。 IntUnaryOperator
は関数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;
}
};
}
};
括弧を追加すると、これがより明確になる場合があります。
IntFunction<IntUnaryOperator> curriedAdd = a -> (b -> (a + b));
または、おそらく中間変数が役立つ場合があります。
IntFunction<IntUnaryOperator> curriedAdd = a -> {
IntUnaryOperator op = b -> a + b;
return op;
};
より明確にするために、そのラムダ式を括弧で書き直しましょう:
IntFunction<IntUnaryOperator> curriedAdd = a -> (b -> (a + b));
したがって、int
を返すFunction
を取る関数を宣言しています。より具体的には、返される関数はint
を取り、int
(2つの要素の合計)を返します。これは IntUnaryOperator
として表すことができます=。
したがって、curriedAdd
はint
を取り、IntUnaryOperator
を返す関数であるため、 IntFunction<IntUnaryOperator>
。
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
IntFunction
を見ると、より明確になるかもしれません:_IntFunction<R>
_はFunctionalInterface
です。 int
を取り、タイプR
の値を返す関数を表します。
この場合、戻り型R
もFunctionalInterface
、つまりIntUnaryOperator
です。したがって、first(外部)関数自体が関数を返します。
この場合:int
に適用されると、curriedAdd
はint
を再びとる関数を返すことになっています(そして再び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
_を返します。