2009-04-30 14 views
15

मैं follwing समारोह लिखा है अगर कार्य करें:मुझे कैसे पता चलेगा एक समारोह एफ # में पूंछ पुनरावर्ती

let str2lst str = 
    let rec f s acc = 
     match s with 
     | "" -> acc 
     | _ -> f (s.Substring 1) (s.[0]::acc) 
    f str [] 

मुझे कैसे पता कर सकते हैं अगर एफ # संकलक एक पाश में बदल गया? क्या प्रतिबिंबक का उपयोग किए बिना पता लगाने का कोई तरीका है (मुझे प्रतिबिंबक के साथ कोई अनुभव नहीं है और मुझे सी # पता नहीं है)?

संपादित करें: साथ ही, एक आंतरिक कार्य का उपयोग किये बिना पूंछ रिकर्सिव फ़ंक्शन लिखना संभव है, या लूप के अंदर रहने के लिए आवश्यक है?

इसके अलावा, क्या किसी भी फ़ंक्शन को चलाने के लिए F # std lib में कोई फ़ंक्शन है, हर बार इसे इनपुट के रूप में अंतिम आउटपुट देता है? आइए कहें कि मेरे पास एक स्ट्रिंग है, मैं स्ट्रिंग पर एक फ़ंक्शन चलाने के लिए चाहता हूं, फिर इसे परिणामी स्ट्रिंग पर फिर से चलाएं और ...

+0

यह भी देखें http://stackoverflow.com/questions/5809683/is-my-rec-function-tail-recursive – Brian

उत्तर

22

दुर्भाग्यवश कोई मामूली तरीका नहीं है।

स्रोत कोड को पढ़ने और प्रकारों का उपयोग करना और यह निर्धारित करना मुश्किल है कि निरीक्षण द्वारा कोई पूंछ कॉल है (क्या यह आखिरी बात है ', न कि' कोशिश 'ब्लॉक में), लेकिन दूसरे लोग खुद को समझें और गलतियां करें। कोई आसान स्वचालित तरीका नहीं है (उदाहरण के अलावा जेनरेट कोड का निरीक्षण करना)।

बेशक, आप परीक्षण डेटा के एक बड़े टुकड़े पर अपने कार्य को आजमा सकते हैं और देख सकते हैं कि यह उड़ाता है या नहीं।

एफ # संकलक सभी पूंछ कॉल के लिए .tail आईएल निर्देश उत्पन्न होगा (जब तक संकलक झंडे उन्हें बंद करने के लिए प्रयोग किया जाता है - जब आप डीबगिंग के लिए ढेर फ्रेम रखना चाहते हैं के लिए इस्तेमाल किया), अपवाद के साथ कि सीधे पूंछ पुनरावर्ती कार्यों को लूप में अनुकूलित किया जाएगा। (संपादित करें: मैं आजकल एफ # संकलक भी मामलों में जहां यह साबित कर सकते हैं कि इस कॉल साइट के माध्यम से कोई पुनरावर्ती छोरों देखते हैं में .tail फेंकना करने में विफल रहता लगता है, यह एक अनुकूलन यह देखते हुए कि .tail opcode कई प्लेटफार्मों पर थोड़ी धीमी है।)

'tailcall' एक आरक्षित कीवर्ड है, इस विचार के साथ कि F # का भविष्य संस्करण आपको लिखने की अनुमति दे सकता है

tailcall func args 

और फिर एक चेतावनी/त्रुटि प्राप्त करें यदि यह पूंछ कॉल नहीं है।

केवल वे कार्य जो स्वाभाविक रूप से पूंछ-पुनरावर्ती नहीं हैं (और इस प्रकार एक अतिरिक्त संचयक पैरामीटर की आवश्यकता है) आपको 'आंतरिक कार्य' मुहावरे में 'बल' देंगे।

let rec nTimes n f x = 
    if n = 0 then 
     x 
    else 
     nTimes (n-1) f (f x) 

let r = nTimes 3 (fun s -> s^" is a rose") "A rose" 
printfn "%s" r 
+0

"tailcall" दिलचस्प है, क्योंकि आपने यह कहने के बजाय कॉल की साइट निर्दिष्ट की है पूरे समारोह पर अधिक उपयोगी "tailrec" घोषणा। क्या आपके पास "आंशिक रूप से पूंछ-रिकर्सिव" फ़ंक्शन हो सकता है? –

+3

@StephenSwensen आप बिल्कुल कर सकते हैं। नियंत्रण प्रवाह शाखाओं एक पूंछ कॉल और एक कॉल है कि एक पूंछ कॉल नहीं है के बीच एक वैकल्पिक करने के लिए ले जा सकता है, और आप केवल एक है कि वास्तव में संकलन समय पर पूंछ कॉल है की जाँच कर सकते हैं। ', आरईसी च एक्स = x> 0 अगर फिर f (1 + x) और 0 + F (1 + x)' अवधारणा को दिखाता जाने हालांकि स्पष्ट रूप से इसे समाप्त नहीं होता। –

2

मैं अंगूठे का नियम पॉल ग्राहम में निरूपण लिस्प पर पसंद:

यहाँ आप क्या पूछा की एक कोड नमूना है अगर वहाँ काम ऐसा करने के लिए, उदाहरण के लिए छोड़ दिया है रिकर्सिव कॉल आउटपुट में हेरफेर करना, फिर कॉल पूंछ रिकर्सिव नहीं है।

संबंधित मुद्दे