2016-07-01 14 views
7

मेरे पास एक ऐसा कार्य है जिसमें तारांकित रेखा एक पुनरावर्ती कॉल शामिल संयोजन है। संयोजन के रूप में काम करते हैं, अगर h1 <> h2 तो रिकर्सिव कॉल नहीं किया जाएगा। लेकिन अगर कॉल किया जाता है, तो क्या कंपाइलर अभी भी बैकट्रैक करेगा और true मानों के संयोजन के पूरे समूह को निष्पादित करेगा? या यह इस अनावश्यक कदम को दूर करेगा?क्या निम्न फ़ंक्शन पूंछ रिकर्सिव है?

दूसरे शब्दों में, निम्न कार्य प्रभावी ढंग से पूंछ रिकर्सिव है?

let isExtensionOf<'A when 'A : equality> (lst1 : list<'A>) (lst2 : list<'A>) : bool = 
    let rec helper (currLst1 : list<'A>) (currLst2 : list<'A>) : bool = 
     match currLst1, currLst2 with 
     | h1 :: _, [] -> false 
     | [], _ -> true 
     | h1 :: t1, h2 :: t2 -> (h1 = h2) && (helper t1 t2) // * 
    helper lst1 lst2 

हाँ, मुझे पता है कि तारांकित लाइन if h1 = h2 then helper t1 t2 else false लिखा जाना चाहिए। लेकिन मैं सिर्फ उत्सुक हूँ।

अग्रिम धन्यवाद।

+3

सबसे आसान तरीका सवालों के इन प्रकार का जवाब देने के: एक विशाल सूची है जो आपको लगता है रोग व्यवहार को गति प्रदान और देखो क्या होता होगा में फ़ीड। –

+5

मैं इसे संकलित करना चाहता हूं और फिर ILSpy के साथ परिणामी कोड को देखता हूं। अधिक भरोसेमंद। यह भी ध्यान रखें कि परिणाम अनुकूलन सक्षम हैं या नहीं, इस पर निर्भर करता है। –

+2

वैसे, यह एक पलक बल्लेबाजी किए बिना कार्डिनिटी '1,00,000,000' (एक सौ मिलियन) की सूचियों को संभाला, इसलिए मैं मानता हूं कि मेरे प्रश्न का उत्तर सकारात्मक में दिया जा सकता है। – Shredderroy

उत्तर

7

यह पता लगाने के लिए एक और आसान चाल है कि फ़ंक्शन पूंछ-पुनरावर्ती है अपवाद फेंकना और स्टैक ट्रेस को देखना है। उदाहरण के लिए, आप helper इस प्रकार संशोधित कर सकते हैं:

System.Exception:

let rec helper (currLst1 : list<'A>) (currLst2 : list<'A>) : bool = 
    match currLst1, currLst2 with 
    | h1 :: _, [] -> failwith "!" 
    | [], _ -> failwith "!" 
    | h1 :: t1, h2 :: t2 -> (h1 = h2) && (helper t1 t2) 

आप अब helper [1..10] [1..10] फोन हैं, तो आप एक स्टैक ट्रेस कि इस तरह दिखता है मिलती है:!
FSI_0002.helper [एक] (FSharpList'1 currLst1, FSharpList'1 currLst2) test.fsx में कम से:। लाइन 4
पर $ FSI_0003.main @() त्रुटि के लिए

वजह से बंद कर दिया लेकिन यदि आप कोड को गैर-पूंछ-पुनरावर्ती होने के लिए बदलते हैं - उदाहरण के लिए पुनरावर्ती कॉल पहले (helper t1 t2) && (h1 = h2) बनाने के लिए अंतिम पंक्ति को संशोधित करके, तो स्टैक ट्रेस सभी पुनरावर्ती कॉल दिखाता है:

System.Exception: FSI_0004.helper [ए] (FSharpList'1 currLst1, FSharpList'1 currLst2) test.fsx में: पंक्ति 4
FSI_0004.helper [ए] (FSharpList'1 currLst1, FSharpList'1 currLst2) test.fsx में : लाइन 4
FSI_0004.helper [एक] (FSharpList'1 currLst1, FSharpList'1 currLst2) test.fsx में कम से: लाइन 4
FSI_0004.helper [एक] पर (FSharpList'1 currLst1, FSharpList'1 currLst2) test.fsx में: लाइन 4
FSI_0004.helper [एक] (FSharpList'1 currLst1, FSharpList पर : FSI_0004.helper [एक] (FSharpList'1 currLst1, FSharpList'1 currLst2) test.fsx में कम से लाइन 4
Test.fsx में '1 currLst2): लाइन 4
FSI_0004.helper [ए] (FSharpList'1 currLst1, FSharpList'1 currLst2) में टी में st.fsx: लाइन 4
FSI_0004.helper [एक] (FSharpList'1 currLst1, FSharpList'1 currLst2) test.fsx में कम से: लाइन 4
FSI_0004.helper [एक] (FSharpList'1 currLst1, FSharpList पर ' 1 currLst2) test.fsx में: लाइन 4
FSI_0004.helper [एक] पर (FSharpList'1: लाइन 4
test.fsx में FSI_0004.helper [एक] (FSharpList'1 currLst1, FSharpList'1 currLst2) पर currLst1, FSharpList'1 currLst2) test.fsx में: लाइन 4
$ FSI_0005 पर।मुख्य @()

+0

यदि मुझे कुछ याद नहीं है तो ऐसी विधि केवल रिलीज़ मोड में काम करेगी। डीबग मोड में पूंछ कॉल ऑप्टिमाइज़ेशन अक्षम है (मेरा मतलब है कि गुणों में पूंछ कॉल tailcheckbox उत्पन्न करें)। डीबग मोड में यह चेकबॉक्स डिफ़ॉल्ट रूप से अनचेक किया जाता है। – eternity

6

ILSpy से यह तो दिखेगी:

IL_0000: nop 
    IL_0001: newobj instance void class '<StartupCode$ConsoleApplication3>.$Program'/[email protected]<!!A>::.ctor() 
    IL_0006: stloc.0 
    IL_0007: ldloc.0 
    IL_0008: ldarg.1 
    IL_0009: ldarg.2 
    IL_000a: tail. 
    IL_000c: call !!0 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!!A>, class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!!A>>::InvokeFast<bool>(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<!0, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<!1, !!0>>, !0, !1) 
    IL_0011: ret 
संबंधित मुद्दे