Java 中的这段递归 lambda 调用如何工作

How is this piece of Recursive lambda call in Java working

我最近在 Java 中看到了这段代码。它涉及函数和打印斐波那契数并且有效。

public class AppLambdaSubstitution {

public static Function<Integer, Integer> Y(Function<Function<Integer, Integer>, Function<Integer, Integer>> f) {
    return x -> f.apply(Y(f)).apply(x);
}

public static void main(String[] args) {
    Function<Integer, Integer> fib = Y(
            func -> x -> {
        if (x < 2)
            return x;
        else
            return func.apply(x - 1) + func.apply(x - 2);
    });

    IntStream.range(1,11).
    mapToObj(Integer::valueOf).
    map(fib).forEach(System.out::println);
  }
}

让我感到困惑的部分是return x -> f.apply(Y(f)).apply(x);Y(f)不就是对方法Y的递归调用吗?我们一直用函数 f 作为参数调用它。对我来说,这种对 return 的递归调用没有基本情况。为什么无限递归调用没有溢出?

从根本上说,您忽略了一点,即 x -> f.apply(Y(f)).apply(x); 不会调用 apply,它会 return 调用 Function

这只是一种非常复杂(并且不直观?)的显示套用和递归函数 IMO 的方式。如果您替换一些东西并使其更具可读性,事情会简单得多。

这个构造:

 Function<Function<Integer, Integer>, Function<Integer, Integer>>

根本不需要,因为左边的参数根本没有使用。只需要抓住正确的一个。因此 left 参数可以 是任何东西 (我稍后将用 Supplier 替换它 - 这也不需要,但只是为了证明一点) .

实际上,您在这里只关心 Function,它对 Stream 的每个元素进行实际计算:

 public static Function<Integer, Integer> right() {

    return new Function<Integer, Integer>() {
        @Override
        public Integer apply(Integer x) {
            if (x < 2) {
                return x;
            } else {
                return apply(x - 1) + apply(x - 2);
            }
        }
    };
}

现在您可以编写整个结构:

 Supplier<Function<Integer, Integer>> toUse = () -> right();
 Function<Integer, Integer> fib = curry(toUse);
 IntStream.range(1, 11)
          .mapToObj(Integer::valueOf)
          .map(fib)
          .forEach(System.out::println);

这个Supplier<Function<Integer, Integer>> toUse = () -> right();应该让你明白为什么在前面的例子(Function<Function, Function>)中需要左边的部分 - 只是为了掌握right一个。

如果仔细观察,您可能会注意到 Supplier 完全不需要,因此您甚至可以进一步简化它:

IntStream.range(1, 11)
         .mapToObj(Integer::valueOf)
         .map(right())
         .forEach(System.out::println);