2012-11-21 12 views
8

में पूंछ रिकर्सन और अपवाद मैं उम्र के लिए गुगल रहा हूं और अभी भी जवाब नहीं मिल रहा है। जो मैं समझता हूं उससे .NET 4.5 पर F # 3.0 रननिंग एक रिकर्सिव विधि के लिए पूंछ रिकर्सन का उपयोग नहीं करेगा यदि आवेदक ने कोशिश/पकड़ में कॉल को लपेट लिया है और/या कोशिश/आखिरकार ब्लॉक किया है। स्थिति क्या है यदि कोई कोशिश/पकड़ या प्रयास/अंत में ढेर के कुछ स्तर हैं?एफ #

+0

यदि आप ऐसा फ़ंक्शन चलाते हैं तो क्या होता है? –

उत्तर

14

आप एक try में कुछ (पूंछ) के शरीर पुनरावर्ती क्रिया लपेट हैं ... with ब्लॉक तो समारोह पूंछ पुनरावर्ती अब और नहीं, क्योंकि कॉल फ्रेम पुनरावर्ती कॉल के दौरान खारिज नहीं किया जा सकता है - यह में रहने के लिए की जरूरत है एक पंजीकृत अपवाद हैंडलर के साथ ढेर।

उदाहरण के लिए, मान लीजिए कि आप List के लिए iter समारोह की तरह कुछ है:

let rec iter f list = 
    try 
    match list with 
    | [] ->() 
    | x::xs -> f x; iter f xs 
    with e -> 
    printfn "Failed: %s" e.Message 

जब आप iter f [1;2;3] फोन तो यह अपवाद संचालकों के साथ 4 नेस्ट ढेर फ्रेम पैदा करेगा (और आप with शाखा में rethrow जोड़ा है, तो यह वास्तव में त्रुटि संदेश 4 बार मुद्रित करेगा)।

आप पूंछ-रिकर्सन को तोड़ने के बिना वास्तव में अपवाद हैंडलर नहीं जोड़ सकते हैं। हालांकि, आपको आमतौर पर नेस्टेड अपवाद हैंडलर की आवश्यकता नहीं होती है। लेकिन यह नेस्टेड अपवाद संचालकों का निर्माण नहीं करता और loop अभी भी हो सकता है -

let iter f list = 
    let rec loop list = 
    match list with 
    | [] ->() 
    | x::xs -> f x; loop xs 
    try loop list 
    with e -> printfn "Failed: %s" e.Message 

यह थोड़ा अलग अर्थ है: तो सबसे अच्छा समाधान इतना है कि यह हर पुनरावर्ती कॉल में अपवाद को संभालने के लिए की जरूरत नहीं है समारोह के पुनर्लेखन के लिए है पूरी तरह से पूंछ रिकर्सिव।

एक और विकल्प केवल पर अपवाद हैंडलिंग को पूंछ-रिकर्सिव कॉल को छोड़कर जोड़ना होगा। वास्तव में, एकमात्र चीज जो इस उदाहरण में अपवाद फेंक सकती है वह f पर कॉल है;

let rec iter f list = 
    match list with 
    | [] ->() 
    | x::xs -> 
    try 
     f x 
    with e -> 
     printfn "Failed: %s" e.Message 
    iter f xs