这段Recursive lambda如何在Java中调用

kau*_*kau 7 java recursion lambda fibonacci java-8

我最近在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);
  }
}
Run Code Online (Sandbox Code Playgroud)

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

Eug*_*ene 5

从根本上说,你错过了x -> f.apply(Y(f)).apply(x);不会打电话的apply那一点,它会return是一个Function.

这只是一种非常复杂(并且非直观?)的方式来显示IMO的currying和递归函数.如果你要替换一些东西并使它更具可读性,事情就会简单得多.

这种结构:

 Function<Function<Integer, Integer>, Function<Integer, Integer>>
Run Code Online (Sandbox Code Playgroud)

完全不需要,因为根本没有使用左参数.只需要掌握正确的一个.因此,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);
            }
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

现在你可以用以下内容编写整个构造:

 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);
Run Code Online (Sandbox Code Playgroud)

Supplier<Function<Integer, Integer>> toUse = () -> right();应该让你理解为什么在前面的例子中(Function<Function, Function>)需要左边部分 - 只是为了得到right一个.

如果你看看更接近,你可能注意到了,Supplier完全没有必要,因此你甚至可以进一步简化它:

IntStream.range(1, 11)
         .mapToObj(Integer::valueOf)
         .map(right())
         .forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)