java lambda java-8 currying

¿Qué significa lambda con 2 flechas en Java 8?



java-8 currying (6)

He leído varios tutoriales de Java 8 antes.

En este momento me encontré con el siguiente tema: ¿Java soporta Curry?

Aquí, veo el siguiente código:

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

Entiendo que este ejemplo suma 2 elementos, pero no puedo entender la construcción:

a -> b -> a + b;

De acuerdo con la parte izquierda de la expresión, esta fila debe implementar la siguiente función:

R apply(int value);

Antes de esto, solo conocí lambdas solo con una flecha.


Agregar paréntesis puede aclarar esto:

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

O probablemente la variable intermedia puede ayudar:

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


Reescribamos esa expresión lambda con paréntesis para que quede más claro:

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

Entonces estamos declarando una función tomando un int que devuelve una Function . Más específicamente, la función devuelta toma un int y devuelve un int (la suma de los dos elementos): esto puede representarse como un IntUnaryOperator .

Por lo tanto, curriedAdd es una función que toma un int y devuelve un IntUnaryOperator , por lo que puede representarse como IntFunction<IntUnaryOperator> .


Si expresa esto como sintaxis lambda no abreviada o sintaxis de clase anónima Java pre-lambda, es más claro lo que está sucediendo ...

La pregunta original. ¿Por qué son dos flechas? Simple, hay dos funciones definidas ... La primera función es una función que define la función, la segunda es el resultado de esa función, que también es una función. Cada uno requiere un operador -> para definirlo.

No taquigrafía

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

Pre Lambda antes de 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; } };


Si observa IntFunction<IntUnaryOperator> podría aclararse: IntFunction<R> es una IntFunction<R> FunctionalInterface . Representa una función que toma un int y devuelve un valor de tipo R

En este caso, el tipo de retorno R también es una IntUnaryOperator FunctionalInterface , es decir, un IntUnaryOperator . Entonces, la primera función (externa) en sí misma devuelve una función.

En este caso: cuando se aplica a un int , se supone que curriedAdd devuelve una función que nuevamente toma un int (y devuelve nuevamente int , porque eso es lo que hace IntUnaryOperator ).

En la programación funcional es común escribir el tipo de una función como param -> return_value y ves exactamente eso aquí. Entonces, el tipo de curriedAdd es int -> int -> int (o int -> (int -> int) si te gusta más).

La sintaxis lambda de Java 8 va junto con esto. Para definir dicha función, escribe

a -> b -> a + b

que es muy similar al cálculo lambda real:

λa λb a + b

λb a + b es una función que toma un solo parámetro b y devuelve un valor (la suma). λa λb a + b es una función que acepta un solo parámetro a y devuelve otra función de un solo parámetro. λa λb a + b devuelve λb a + b con a conjunto al valor del parámetro.


Son dos expresiones lambda.

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


Una IntFunction<R> es una función int -> R IntUnaryOperator es una función int -> int .

Por lo tanto, una IntFunction<IntUnaryOperator> es una función que toma un int como parámetro y devuelve una función que toma un int como parámetro y devuelve un 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

Quizás sea más claro si usa clases anónimas para "descomponer" la lambda:

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