我最近在
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); } }
令我困惑的部分是返回x – > f.apply(Y(F)).适用(X);.是不是Y(f)是对方法Y的递归调用?我们一直用函数f作为参数来调用它.对我来说,这种递归调用没有基本情况.为什么无休止的递归调用没有溢出?
解决方法
从根本上说,你错过了x – >的观点. .f.apply(Y(f))的应用(X);不会调用apply,它会返回一个Function.
这只是一种非常复杂(并且非直观?)的方式来显示IMO的currying和递归函数.如果要替换一些东西并使其更具可读性,事情就会简单得多.
这种结构:
Function<Function<Integer,Integer>>
根本不需要,因为根本没有使用左参数.只需要掌握正确的一个.因此左边的参数可以是任何东西(我稍后会用供应商替换它 – 也不需要,但只是为了证明一点).
实际上你在这里关心的是这个函数,它为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);
该供应商<功能<整数,整数>> toUse =() – >对();应该让你理解为什么在前面的例子中(函数< Function,Function>)需要左边部分 – 只是为了得到正确的一部分.
如果您看得更近,您可能会注意到完全不需要供应商,因此您甚至可以通过以下方式进一步简化:
IntStream.range(1,11) .mapToObj(Integer::valueOf) .map(right()) .forEach(System.out::println);