21

मैंने अपनी भाषा में क्लोजर (लैम्बडास) जोड़ना शुरू किया जो एलएलवीएम का बैकएंड के रूप में उपयोग करता है। मैंने उन्हें सरल मामलों के लिए लागू किया है, जहां उन्हें हमेशा परिभाषित किया जा सकता है यानी क्लोजर परिभाषा के लिए कोड को उत्पन्न करने की आवश्यकता नहीं होती है, क्योंकि इसका उपयोग कहीं भी किया जाता है।एलएलवीएम आईआर में बंद करने में कुशलतापूर्वक कार्यान्वयन कैसे करें?

लेकिन बंद होने पर हमेशा बंद करने के लिए कोड को कैसे उत्पन्न किया जाए (उदाहरण के लिए, यह किसी अन्य फ़ंक्शन को पास किया गया है जो रेखांकित नहीं है)। अधिमानतः, कॉल साइटों को परवाह नहीं करना चाहिए कि वे नियमित कार्य या बंद कर चुके हैं और उन्हें सामान्य कार्यों के रूप में बुलाएंगे।

मैं सिंथेटिक नाम के साथ एक फ़ंक्शन उत्पन्न कर सकता हूं, लेकिन इसे संदर्भ तर्क को अतिरिक्त तर्क के रूप में लेना होगा और यह फ़ंक्शन केवल किसी अन्य फ़ंक्शन पर नहीं भेजा जा सकता है जो आवश्यक अतिरिक्त तर्क के बारे में नहीं जानता है।

मैंने एलएलवीएम के ट्रैम्पोलिन इंट्रिनिक्स का उपयोग करके एक संभावित समाधान के बारे में सोचा है, जो एक फ़ंक्शन से एक पैरामीटर "एक्साइज" करता है, एक पॉइंटरोलिन फ़ंक्शन में पॉइंटर लौटाता है जो एक कम पैरामीटर लेता है। इस मामले में, अगर बंद करने के लिए उत्पन्न फ़ंक्शन ने संदर्भ पैरामीटर को पहले पैरामीटर के रूप में लिया, तो मैं इसे एक्साइज कर सकता हूं और एक फ़ंक्शन वापस प्राप्त कर सकता हूं जो वास्तव में बंद होने के रूप में कई पैरामीटर लेता है। क्या यह ध्वनि करने योग्य है? कुशल? क्या कोई बेहतर समाधान है?

कोड उदाहरण:

def applyFunctionTo(value: Int, f: (Int) -> Int) = f(value) 

def main() = { 
    val m := 4; 
    val n := 5; 
    val lambda := { (x: Int) => x + m + n }; 
    applyFunctionTo(3, lambda) 
} 

अब, चलो कल्पना है कि इस def main() = 3 + 4 + 5 को inlined नहीं होता है, और applyFunctionTo संभवतः अलग से संकलित किया जाएगा कि, और हम वहाँ कॉल साइट बदल नहीं सकते। ट्रैम्पोलाइनिंग के साथ, मैं कल्पना उत्पन्न कोड कुछ इस तरह होगा (स्यूडोकोड में व्यक्त किया, * सूचक का मतलब है):

def main$lambda$1(env: {m: Int, n: Int}*, x: Int) = x + env.m + env.n 
def main() = { 
    m = 4 
    n = 5 
    env* = allocate-space-for {Int, Int} 
    env = {m, n} 
    tramp* = create-trampoline-for(main$lambda$1*, env*) 
    return applyFunctionTo(3, tramp*) 
    // release memory for env and trampoline if the lambda didn't escape 
} 

यह सही नहीं लगता है?

+0

आभासी तरीकों के साथ बंद करने और वस्तुओं को कार्यान्वित करने के बीच कोई अंतर नहीं है। –

+0

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

+0

मेरा मतलब है कि बंद करने के लिए कुछ नया आविष्कार करने का कोई कारण नहीं है: आप एक ही बात कर सकते हैं, कहें, एक सी ++ कंपाइलर पहले से ही कर रहा है।संभावना है कि यह करने के लिए पहले से ही सबसे कुशल चीज है। –

उत्तर

7

निष्पादन योग्य और कुशल लगता है।

वैकल्पिक तरीका, जिसे ट्रैम्पोलिन की आवश्यकता नहीं है, को क्लोजर प्रकार को फ़ंक्शन पॉइंटर और पॉइंटर की पर्यावरण यानी स्टैक पॉइंटर के रूप में परिभाषित करना है। सी कॉलिंग सम्मेलन में अतिरिक्त तर्कों को नजरअंदाज कर दिया जाता है ताकि यदि आप पर्यावरण को अंतिम तर्क के रूप में प्रदान करते हैं तो आप नियमित फ़ंक्शन के लिए कॉलबैक के रूप में (function_ptr, null) का उपयोग भी कर सकते हैं।

+0

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

1

एक गूंगा विचार यह होगा कि प्रत्येक बंद करने के लिए आप आवश्यक डेटा को पकड़ने के लिए एक थ्रेड स्थानीय संरचना उत्पन्न करते हैं (स्थानीय संरचना, या कई पॉइंटर्स के लिए केवल एक सूचक हो सकता है)।

बंद करने का निर्माता टीएलएस चर सेट करने और उनके पास मौजूद राज्य को "सहेजने" के लिए ज़िम्मेदार है (रिकर्सिव कॉल की अनुमति देने के लिए)।

उपयोगकर्ता तब सामान्य रूप से फ़ंक्शन को कॉल करता है, इसे निष्पादित किया जाता है और वातावरण का उपयोग करता है।

कॉल के बाद, बंद करने का निर्माता मूल मूल्यों को टीएलएस चर में "पुनर्स्थापित करता है"।

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