Java 8 中带有 2 个箭头的 lambda 是什么意思?

What does lambda with 2 arrows mean in Java 8?

我已经阅读了几个 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); 

在此之前,我只用一个箭头就遇到了 lambdas。

如果您将其表达为非shorthand lambda 语法或pre-lambda Java 匿名class 语法,则发生的事情会更清楚...

原题。为什么是两个箭头?很简单,定义了两个函数...第一个函数是函数定义函数,第二个是该函数的结果,它也恰好是函数。每个都需要一个 -> 运算符来定义它。

非shorthand

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

Java 8

之前的 Pre-Lambda
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 -> RIntUnaryOperator 是一个函数 int -> int.

因此,IntFunction<IntUnaryOperator> 是一个以 int 作为参数的函数,而 return 是一个以 int 作为参数和 return 的函数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

如果使用匿名 类 到 "decompose" 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;
            }
        };
    }
};

让我们用括号重写 lambda 表达式,使其更清晰:

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

所以我们声明一个函数接受一个 int,其中 returns 一个 Function。更具体地说,返回的函数采用 int 和 returns 和 int(两个元素的总和):这可以表示为 IntUnaryOperator.

因此,curriedAdd是一个接受int并返回IntUnaryOperator的函数,所以它可以表示为IntFunction<IntUnaryOperator>.

添加括号可能会更清楚:

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

或者中间变量可能有帮助:

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

如果您查看 IntFunction,它可能会变得更清楚:IntFunction<R> 是一个 FunctionalInterface。它表示一个函数,该函数采用 int 和 return 类型的值 R.

在这种情况下,return类型R也是一个FunctionalInterface,即一个IntUnaryOperator。所以 first(外部)函数本身 return 是一个函数。

在这种情况下:当应用于 int 时,curriedAdd 应该 return 一个函数,该函数再次采用 int(和 return又是 int,因为那是 IntUnaryOperator 所做的)。

在函数式编程中,将函数类型写成 param -> return_value 很常见,您可以在此处看到。所以curriedAdd的类型是int -> int -> int(或者int -> (int -> int),如果你更喜欢的话)。

Java 8 的 lambda 语法与此相符。要定义这样一个函数,你写

a -> b -> a + b

这与实际的 lambda 演算非常相似:

λa λb a + b

λb a + b 是一个函数,它采用单个参数 b 和 returns 一个值(总和)。 λa λb a + b是一个接受单参数的函数,a和return是另一个单参数的函数。 λa λb a + b returns λb a + b with a set to the parameter value.

是两个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