2017-09-22 9 views
7

मैं हाल ही में जावा में कोड के इस टुकड़े में आया था। इसमें फंक्शन और प्रिंटिंग फाइबोनैकी संख्या शामिल है और यह काम करता है।जावा में रिकर्सिव लैम्ब्डा कॉल का यह टुकड़ा कैसे काम करता है

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

'वाई (च)' कॉल एक लैम्ब्डा के अंदर है , और वह लैम्ब्डा केवल तभी निष्पादित हो जाता है जब 'एफ' इसे कॉल करने का विकल्प चुनता है। – 4castle

+4

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

उत्तर

5

मूलरूप आप बात को अनदेखा कर रहे हैं कि x -> f.apply(Y(f)).apply(x);apply, यह return एक Function फोन नहीं होंगे।

यह करी और रिकर्सिव फ़ंक्शन आईएमओ दिखाने का एक बहुत ही जटिल (और अंतर्ज्ञानी?) तरीका है। यदि आप कुछ चीजों को प्रतिस्थापित करेंगे और इसे थोड़ा अधिक पठनीय बना देंगे तो चीजें बहुत सरल होंगी।

इस निर्माण:

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

अब आप के साथ है कि पूरे निर्माण लिख सकते हैं:

असल में सब तुम यहाँ के बारे में परवाह इस Function कि Stream के प्रत्येक तत्व के लिए वास्तविक गणना करता है आपको समझना चाहिए कि पिछले उदाहरण में क्यों (Function<Function, Function>) बाएं भाग की आवश्यकता थी - बसको पकड़ने के लिएएक।

तुम भी करीब देखो, तो आप देख सकते हैं कि Supplier है पूरी तरह की जरूरत नहीं है, इस प्रकार आप आगे भी साथ इसे आसान बनाने सकता है:

IntStream.range(1, 11) 
     .mapToObj(Integer::valueOf) 
     .map(right()) 
     .forEach(System.out::println); 
संबंधित मुद्दे