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