2017-09-22 1 views
7

최근 Java에서이 코드 조각을 발견했습니다. 그것은 함수와 피보나치 수를 인쇄하는 것과 관련이 있습니다.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을 매개 변수로 사용하여 계속 호출합니다. 나에게 돌아가는 재귀 호출에는 기본 케이스가 없다. 무한 재귀 호출로 인해 오버플로가 발생하지 않는 이유는 무엇입니까?

+3

은'Y는 (F)'호출 람다 내부 : 당신이 더 가까이 보면

, 당신은 완전히 필요하지 Supplier 따라서 당신은 더욱 그것을 단순화 할 수 있음을 알 수 있습니다 , 그리고'f'가 그것을 호출하기를 원한다면 lambda는 단지 실행될 것입니다. – 4castle

+4

https://en.wikipedia.org/wiki/Fixed-point_combinator – pvg

답변

5

기본적으로 x -> f.apply(Y(f)).apply(x);apply이 아니기 때문에 returnFunction입니다.

이것은 매우 복잡하고 직관적이지 않은 currying 및 recursive function IMO를 보여주는 방법입니다. 두 가지를 대체하고 좀 더 읽기 쉽게 만들면 상황이 훨씬 더 간단해질 것입니다.

이 건설 : 왼쪽 매개 변수가되지 전혀을 사용하기 때문에

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

은 전혀 필요하지 않습니다. 올바른 것의 파악이 필요합니다. 따라서 left 매개 변수는 일 수 있으며, 나중에는이 될 수 있습니다. 나중에이 값을 Supplier으로 바꿀 것입니다. 이는 그 중 하나 일 필요는 없지만 요점을 증명하기위한 것입니다.

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(); :

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); 
      } 
     } 
    }; 
} 

지금 당신이 그 전체 구조를 작성할 수

사실 당신이 여기에 관심을 모두 Stream의 각 요소에 대해 실제 계산을 수행이 Function입니다 이전 예 (Function<Function, Function>)에서 의 왼쪽 부분 인이 필요한 이유를 이해해야합니다.를 만회하면됩니다.하나.

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