बाइंडरों के उपयोग से एक फ़ंक्शन के साथ बाध्य चर का प्रतिनिधित्व करना


11

सिंटैक्स में बाध्य चर का प्रतिनिधित्व करने की समस्या, और विशेष रूप से जो कैप्चर-अवॉइड प्रतिस्थापन से संबंधित है, अच्छी तरह से ज्ञात है और इसके कई समाधान हैं: अल्फा-समतुल्यता, डी ब्रुइजन सूचकांकों के साथ नामांकित चर, स्थानीय रूप से नामहीनता, नाममात्र सेट आदि।

लेकिन एक और स्पष्ट दृष्टिकोण प्रतीत होता है, जिसे मैंने अभी तक कहीं भी इस्तेमाल नहीं किया है। अर्थात्, बुनियादी वाक्य रचना में हम केवल एक "चर" शब्द लिखा कहने , और फिर अलग से हम एक समारोह में एक बांधने की मशीन जिसका गुंजाइश यह निहित करने के लिए प्रत्येक चर नक्शे दे। तो एक λ की तरहλ

λx.(λy.xy)

लिखा जाएगा , और समारोह पहला नक्शा होगा पहले λ और दूसरा दूसरे को λ । तो यह डी ब्रूजन सूचकांकों की तरह है, केवल " λ s" को गिनने के बजाय, जब आप संबंधित बाइंडर को खोजने के लिए शब्द से वापस आते हैं, तो आप केवल एक फ़ंक्शन का मूल्यांकन करते हैं। (यदि इसे कार्यान्वयन में डेटा संरचना के रूप में दर्शाया जाता है, तो मैं प्रत्येक चर-अवधि की वस्तु को एक साधारण सूचक / संबंधित बाइंडर-टर्म ऑब्जेक्ट के संदर्भ में लैस करने के बारे में सोचूंगा।)λ.(λ.)λλλ

जाहिर है कि यह पढ़ने के लिए मनुष्यों के लिए एक पृष्ठ पर वाक्यविन्यास लिखने के लिए समझदार नहीं है, लेकिन फिर न तो डे ब्रूजन सूचकांकों हैं। यह मुझे लगता है कि यह गणितीय रूप से सही समझ में आता है, और विशेष रूप से यह कैप्चरिंग से बचने के प्रतिस्थापन को बहुत आसान बना देता है: जिस शब्द को आप प्रतिस्थापित कर रहे हैं उसमें बस छोड़ दें और बाध्यकारी कार्यों का संघ लें। यह सच है कि इसमें "फ्री वैरिएबल" की धारणा नहीं है, लेकिन फिर (फिर से) न तो वास्तव में डे ब्रूजन इंडेक्स करते हैं; या तो मामले में मुक्त चर वाले शब्द को "संदर्भ" की सूची के साथ एक शब्द का प्रतिनिधित्व किया जाता है, जो सामने होता है।

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


2
मैं कमियों के बारे में नहीं जानता। शायद औपचारिकता (उदाहरण के लिए एक सहायक सहायक) में भारी है? मुझे यकीन नहीं है ... मुझे क्या पता है कि तकनीकी रूप से कुछ भी गलत नहीं है: लैम्बडा-टर्म्स देखने का यह तरीका प्रूफ नेट के रूप में उनके प्रतिनिधित्व द्वारा सुझाया गया है, इसलिए प्रूफ-नेट-जागरूक लोग (खुद की तरह) इसका इस्तेमाल करते हैं पुरे समय। लेकिन सबूत-शुद्ध-जागरूक लोग बहुत दुर्लभ हैं :-) इसलिए शायद यह वास्तव में परंपरा की बात है। पुनश्च: मैंने प्रश्न को अधिक दृश्यमान (उम्मीद) बनाने के लिए कुछ संबंधित टैग जोड़े।
डैमियानो मजाज़

क्या यह दृष्टिकोण उच्च-क्रम अमूर्त वाक्य रचना के बराबर नहीं है (अर्थात, मेजबान भाषा में कार्यों के रूप में बाँध का प्रतिनिधित्व करता है)? एक अर्थ में, एक फ़ंक्शन का उपयोग बाइंडर के रूप में करने से क्लोजर के प्रतिनिधित्व में, बाइंडरों को अंतर्निहित रूप से स्थापित किया जाता है।
रोडोलफ लेपिग्रे सेप

2
@RodolpheLepigre मुझे ऐसा नहीं लगता। विशेष रूप से, मेरी समझ यह है कि एचएएएस केवल तभी सही होता है जब मेटाथोरी काफी कमजोर होती है, जबकि यह दृष्टिकोण मनमाने ढंग से मेटेट्री में सही होता है।
माइक शुलमैन

3
ठीक है, इसलिए प्रत्येक बाइंडर एक अद्वितीय (पेड़ के भीतर) चर नाम का उपयोग करता है (इसके लिए सूचक स्वचालित रूप से एक है)। यह बारेंड्रेगट सम्मेलन है। लेकिन जब आप स्थानापन्न करते हैं, तो आपको (C) उस चीज़ का पुनर्निर्माण करना चाहिए जिसे आप अद्वितीय नाम रखने के लिए प्रतिस्थापित कर रहे हैं। अन्यथा (सामान्य रूप में) आप कई सबट्रेयर्स के लिए एक ही पॉइंटर्स का उपयोग कर रहे हैं, और वेरिएबल कैप्चर प्राप्त कर सकते हैं। पुनर्निर्माण अल्फा नामकरण है। वर्तमान में सेट के रूप में पेड़ों के आपके एन्कोडिंग की बारीकियों के आधार पर कुछ ऐसा ही होता है?
डैन डैल

3
@DanDoel आह, दिलचस्प। मुझे लगा कि यह स्पष्ट नहीं है कि उल्लेख करने की आवश्यकता नहीं है कि आप चर की हर घटना पर प्रतिस्थापित शब्द की एक अलग प्रति में छोड़ देंगे जिसे इसके लिए प्रतिस्थापित किया जा रहा है; अन्यथा आपके पास कोई सिंटेक्स ट्री नहीं होगा ! यह मेरे लिए इस नाम को अल्फा-रीनेमिंग के रूप में समझने के लिए नहीं हुआ, लेकिन अब जब आप इसे इंगित करते हैं तो मैं इसे देख सकता हूं।
माइक शुलमैन

जवाबों:


11

Andrej के'sukasz के उत्तर अच्छे अंक लाते हैं, लेकिन मैं अतिरिक्त टिप्पणियां जोड़ना चाहता था।

दमिआनो ने जो कहा, उसे इंगित करने के लिए बाइंडरों का उपयोग करके बाइंडिंग का प्रतिनिधित्व करने का यह तरीका प्रूफ-नेट्स द्वारा सुझाया गया है, लेकिन सबसे पहला स्थान जहां मैंने इसे लैम्ब्डा शब्दों के लिए देखा था, नूथ द्वारा एक पुराने निबंध में था:

  • डोनाल्ड नुथ (1970)। औपचारिक शब्दार्थ के उदाहरण। में संगोष्ठी पर एल्गोरिथम बोली का अर्थ विज्ञान , ई Engeler (सं।), गणित 188, स्प्रिंगर में व्याख्यान नोट्स।

पेज 234 के बारे में उन्होंने निम्न आरेख (जिसे उन्होंने एक "जानकारी संरचना" कहा जाता है) शब्द का प्रतिनिधित्व आकर्षित किया :(λy.λz.yz)x

$ के लिए नथ का आरेख (\ lambda y। \ Lambda z.yz) x $ है

इस प्रकार के लंबोदर शब्दों का चित्रमय प्रतिनिधित्व 1970 के दशक की शुरुआत में दो शोधों में स्वतंत्र रूप से (और अधिक गहराई से) किया गया था, क्रिस्टोफर वड्सवर्थ (1971, लैम्बडा -कैलकुलस के शब्दार्थ और प्रगति ) और रिचर्ड स्टेटमैन (1974, संरचनात्मक जटिलता ) द्वारा सबूत के )। आजकल, ऐसे आरेखों को अक्सर "λ-graphs" के रूप में संदर्भित किया जाता है (उदाहरण के लिए इस पेपर को देखें )।

ध्यान रखें कि नूथ के आरेख में शब्द रैखिक है , इस अर्थ में कि प्रत्येक स्वतंत्र या बाध्य चर बिल्कुल एक बार होता है - जैसा कि दूसरों ने उल्लेख किया है, गैर-तुच्छ मुद्दे हैं और इस तरह के प्रतिनिधित्व को गैर में विस्तारित करने की कोशिश में किए जाने वाले विकल्प हैं -विरोधी शर्तें।

α


10

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

पर्पस के उत्तर पर आपकी टिप्पणी से मुझे लगा कि कुछ हद तक आप साझा करने में रुचि रखते हैं। मैं यहां कुछ इनपुट प्रदान कर सकता हूं।

एक विशिष्ट टाइप किए गए लैम्ब्डा कैलकुलस में, कमजोर पड़ना और सिकुड़ना, अन्य नियमों के विपरीत, सिंटैक्स नहीं होता है।

Γt:TΓ,x:At:TW
Γ,x1:A,x2:At:TΓ,x:At:TC

आइए कुछ वाक्य रचना जोड़ें:

Γt:TΓ,x:AWx(t):TW
Γ,x1:A,x2:At:TΓ,x:ACxx1,x2(t):TC

Cab,c()ab,c

उस वाक्य रचना के साथ, प्रत्येक चर का उपयोग दो बार किया जाता है, एक बार जहां यह बाध्य होता है और एक बार जहां इसका उपयोग किया जाता है। यह हमें एक विशेष वाक्य रचना से खुद को दूर करने और शब्द को एक ग्राफ के रूप में देखने की अनुमति देता है जहां चर और शब्द किनारों हैं।

एल्गोरिथम जटिलता से, हम अब एक चर से एक बांधने की मशीन के लिए नहीं, बल्कि बांधने से चर तक बिंदुओं का उपयोग कर सकते हैं और निरंतर समय में प्रतिस्थापन कर सकते हैं।

इसके अलावा, यह सुधार हमें और अधिक निष्ठा के साथ क्षरण, नकल और साझाकरण को ट्रैक करने की अनुमति देता है। एक नियम लिख सकते हैं कि अवमानना ​​साझा करते समय एक शब्द की प्रतिलिपि बनाएँ (या मिटाएँ)। ऐसा करने के कई तरीके हैं। कुछ प्रतिबंधित सेटिंग्स में जीत काफी आश्चर्यजनक है

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

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


6

आपकी डेटा संरचना काम करती है, लेकिन यह अन्य तरीकों की तुलना में अधिक कुशल नहीं होगी क्योंकि आपको प्रत्येक बीटा कमी पर प्रत्येक तर्क की प्रतिलिपि बनाने की आवश्यकता होती है, और आपको कई प्रतियों को बनाना होगा क्योंकि बाध्य चर की घटनाएं होती हैं। इस तरह आप सबटम्स के बीच मेमोरी शेयरिंग को नष्ट करते रहते हैं। इस तथ्य के साथ संयुक्त है कि आप एक गैर-शुद्ध समाधान का प्रस्ताव कर रहे हैं जिसमें सूचक जोड़तोड़ शामिल हैं, और इसलिए बहुत त्रुटि-प्रवण है, यह संभवतः परेशानी के लायक नहीं है।

लेकिन मुझे एक प्रयोग देखकर खुशी होगी! आप lambdaइसे अपने डेटा-स्ट्रक्चर के साथ ले सकते हैं और लागू कर सकते हैं (OCaml में संकेत हैं, उन्हें संदर्भ कहा जाता है )। कम या ज्यादा, तुम बस को बदलने के लिए syntax.mlऔर norm.mlअपने संस्करणों के साथ। यह कोड की 150 लाइनों से कम है।


धन्यवाद! मैं मानता हूं कि मैं वास्तव में कार्यान्वयन के बारे में बहुत कठिन नहीं सोच रहा था, लेकिन मुख्य रूप से डी ब्रूजन बहीखाता पद्धति या अल्फा-रीनेमिंग के बारे में परेशान किए बिना गणितीय प्रमाण करने में सक्षम था। लेकिन क्या कोई मौका है कि एक कार्यान्वयन कुछ मेमोरी साझाकरण को "आवश्यक होने तक", यानी जब तक प्रतियां एक-दूसरे से अलग नहीं होंगी, तब तक कोई साझाकरण साझा नहीं कर सकता है?
माइक शुलमैन

β(λx.e1)e2e1e2

2
गणितीय प्रमाणों के बारे में, अब मैं टाइप-थ्योरिटिक सिंटैक्स के औपचारिककरण के एक अच्छे सौदे से गुजरा हूं, मेरा अनुभव यह है कि फायदे तब प्राप्त होते हैं जब हम सेटअप को सामान्य करते हैं और इसे अधिक सारगर्भित बनाते हैं, तब नहीं जब हम इसे और अधिक ठोस बनाते हैं। उदाहरण के लिए, हम "बाइंडिंग के उपचार के किसी भी अच्छे तरीके" के साथ वाक्य रचना को परिमित कर सकते हैं। जब हम ऐसा करते हैं, तो गलतियाँ करना अधिक कठिन होता है। मैंने डे ब्रूजन सूचकांकों के साथ टाइप थ्योरी को भी औपचारिक रूप दिया है। यह बहुत भयानक नहीं है, खासकर अगर आपके पास निर्भर प्रकार हैं जो आपको निरर्थक चीजें करने से रोकते हैं।
बाउर

2
जोड़ने के लिए, मैंने एक कार्यान्वयन पर काम किया है जो मूल रूप से इस तकनीक का उपयोग करता है (लेकिन अद्वितीय पूर्णांक और नक्शे, न कि पॉइंटर्स), और मैं वास्तव में इसकी सिफारिश नहीं करूंगा। हमारे पास निश्चित रूप से बहुत सारे कीड़े थे जहां हम क्लोनिंग चीजों को ठीक से याद करते थे (जब संभव हो तो इसे बचने की कोशिश करने के कारण कोई छोटा हिस्सा नहीं)। लेकिन मुझे लगता है कि कुछ जीएचसी लोगों द्वारा एक पेपर है जहां वे इसकी वकालत करते हैं (वे अद्वितीय नामों को उत्पन्न करने के लिए हैश फ़ंक्शन का उपयोग करते हैं, मुझे विश्वास है)। यह निर्भर करता है कि वास्तव में आप क्या कर रहे हैं। मेरे मामले में यह प्रकार की जाँच / जाँच थी, और यह बहुत खराब लगता है कि वहाँ अनुकूल है।
दान डोले

@MikeShulman उचित (प्राथमिक) जटिलता के एल्गोरिदम के लिए (प्रतिलिपि बनाने और मिटाने की एक बड़ी मात्रा में), लैम्पिंग के इष्टतम कमी के तथाकथित 'सार भाग' आवश्यक होने तक प्रतियां नहीं बना रहा है। सार भाग पूर्ण एल्गोरिथ्म के विपरीत गैर-विवादास्पद भाग भी है जिसमें कुछ एनोटेशन की आवश्यकता होती है जो गणना पर हावी हो सकते हैं।
सुकस लेव

5

अन्य जवाब ज्यादातर कार्यान्वयन मुद्दों पर चर्चा कर रहे हैं। चूंकि आप अपने मुख्य प्रेरणा का उल्लेख बहुत अधिक बहीखाता के बिना गणितीय प्रमाणों के रूप में करते हैं, यहाँ मुख्य मुद्दा यह है कि मैं इसके साथ देखता हूं।

जब आप कहते हैं कि "एक ऐसा फंक्शन जो प्रत्येक वैरिएबल को एक बाइंडर को मैप करता है, जिसके दायरे में यह निहित है": इस फंक्शन का आउटपुट प्रकार निश्चित रूप से थोड़ा सा सबटलर है, जो इसे ध्वनि बनाता है! विशेष रूप से, फ़ंक्शन को "विचार के तहत अवधि के बांधने वाले" जैसे कुछ मूल्यों को लेना चाहिए - यानी कुछ सेट जो शब्द के आधार पर भिन्न होते हैं (और स्पष्ट रूप से किसी भी उपयोगी तरीके से एक बड़ा परिवेश सेट का सबसेट नहीं है)। इसलिए प्रतिस्थापन में, आप केवल "बाध्यकारी कार्यों के संघ को नहीं ले सकते हैं": आपको प्रतिस्थापन के परिणाम में बाइंडरों से मूल शर्तों के अनुसार कुछ मानचित्रों के अनुसार उनके मानों को फिर से जोड़ना होगा।

ये रीइन्डेक्सिंग निश्चित रूप से "रूटीन" होनी चाहिए, इस अर्थ में कि वे या तो गलीचा के नीचे बह सकते हैं, या किसी प्रकार की फंतासी या स्वाभाविकता के संदर्भ में अच्छी तरह से पैक किए जा सकते हैं। लेकिन नामांकित चर के साथ काम करने में शामिल बहीखाता पद्धति के बारे में भी यही सच है। तो कुल मिलाकर, यह मेरे लिए संभावना है कि अधिक से अधिक मानक दृष्टिकोण के साथ इस दृष्टिकोण के साथ कम से कम बहीखाता पद्धति शामिल होगी।

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


प्रत्येक चर के दायरे पर नज़र रखने के लिए वास्तव में बहीखाता पद्धति की आवश्यकता होती है, लेकिन इस निष्कर्ष पर न जाएं कि किसी को हमेशा अच्छी तरह से सिंटैक्स को प्रतिबंधित करना होगा! प्रतिस्थापन और बीटा कमी जैसे ऑपरेशनों को बीमार-स्कोप की शर्तों पर भी परिभाषित किया जा सकता है, और मेरा संदेह यह है कि अगर कोई इस दृष्टिकोण को औपचारिक रूप देना चाहता था (जो फिर से, प्रमाण-जाल / "λ-graphs" का दृष्टिकोण है) प्रूफ असिस्टेंट, सबसे पहले अधिक सामान्य ऑपरेशनों को लागू करेगा, और फिर साबित करेगा कि वे अच्छी तरह से स्कोप होने की संपत्ति को संरक्षित करते हैं।
नोआम ज़िलबर्गर

(सहमत है कि यह बाहर की कोशिश करने लायक है ... हालांकि मुझे आश्चर्य नहीं होगा अगर किसी के पास पहले से ही प्रमाण-जाल / λ-रेखांकन को औपचारिक बनाने के संदर्भ में है।)
नोम ज़िलबर्गर


5

λLazy.t

कुल मिलाकर, मुझे लगता है कि यह एक अच्छा प्रतिनिधित्व है, लेकिन इसमें बाइंडिंग लिंक को तोड़ने से बचने के लिए पॉइंटर्स के साथ कुछ बहीखाता शामिल है। मुझे लगता है कि परस्पर क्षेत्रों का उपयोग करने के लिए कोड को बदलना संभव होगा, लेकिन फिर कोक में एन्कोडिंग कम प्रत्यक्ष होगी। मुझे अभी भी यकीन है कि यह HOAS से काफी मिलता-जुलता है, हालांकि पॉइंटर संरचना स्पष्ट है। हालांकि, Lazy.tइसका मतलब है कि कुछ कोड का गलत समय पर मूल्यांकन किया जाना संभव है। मेरे कोड में ऐसा नहीं है क्योंकि एक चर के साथ केवल एक चर का प्रतिस्थापन forceसमय पर हो सकता है (और उदाहरण के लिए मूल्यांकन नहीं)।

(* Representation of a term of the λ-calculus. *)
type term =
  | FVar of string      (* Free variable  *)
  | BVar of bvar        (* Bound variable *)
  | Appl of term * term (* Application    *)
  | Abst of abst        (* Abstraction    *)

(* A bound variable is a pointer to the corresponding binder. *)
and bvar = abst

(* A binder is represented as its body in which the bound variable points to
   the binder itself. Note that we need to use a thunk to be able to work
   underneath a binder (for substitution, evaluation, ...). A name can be
   given for easy printing, but no renaming is done. Only “visual capture”
   can happen since pointers are established the right way, even if names
   can clash. *)
and abst = { body : term Lazy.t ; name : string }

(* Terms can be built with recursive values for abstractions. *)

(* Krivine's notation is used for application (function in parentheses). *)

let id    : term = (* λx.x        *)
  Abst(let rec id = {body = lazy (BVar(id)); name = "x"} in id)

let idid  : term = (* (λx.x) λx.x *)
  Appl(id, id)

let delta : term = (* λx.(x) x *)
  Abst(let rec d = {body = lazy (Appl(BVar(d), BVar(d))); name = "x" } in d)

let weird : term = (* (λx.x) λy.(λx.(x) x) (C) y *)
  Appl(id, Abst(let rec x = {body = lazy (Appl(delta, Appl(FVar("C"),
    BVar(x)))); name = "y"} in x))

let omega : term = (* (λx.(x) x) λx.(x) x *)
  Appl(delta, delta)

(* Printing function is immediate. *)
let rec print : out_channel -> term -> unit = fun oc t ->
  match t with
  | FVar(x)   -> output_string oc x
  | BVar(x)   -> output_string oc x.name
  | Appl(t,u) -> Printf.fprintf oc "(%a) %a" print t print u
  | Abst(f)   -> Printf.fprintf oc "λ%s.%a" f.name print (Lazy.force f.body)

(* Substitution of variable [x] by [v] in the term [t]. Occurences of [x] in
   [t] are identified using physical equality ([BVar] case). The subtle case
   is [Abst], because we need to reestablish the physical link between the
   binder and the variable it binds. *)
let rec subst_var : bvar -> term -> term -> term = fun x t v ->
  match t with
  | FVar(_)   -> t
  | BVar(y)   -> if y == x then v else t
  | Appl(t,u) -> Appl(subst_var x t v, subst_var x u v)
  | Abst(f)   ->
      (* First compute the new body. *)
      let fv = subst_var x (Lazy.force f.body) v in
      (* Reestablish the physical link, using [subst_var] itself again. This
         requires a second traversal of the term. We could probably do both
         at once, but who cares the complexity is linear in [t] anyway. *)
      Abst(let rec g = {f with body = lazy (subst_var f fv (BVar(g)))} in g)

(* Actual substitution function. *)
let subst : abst -> term -> term = fun f v ->
  subst_var f (Lazy.force f.body) v

(* Normalization function (all the way, even under binders). *)
let rec eval : term -> term = fun t ->
  match t with
  | Appl(t,u) ->
      begin
        let v = eval u in
        match eval t with
        | Abst(f) -> eval (subst f v)
        | t       -> Appl(t,v)
      end
  | Abst(f)   ->
      (* Actual computation in the body. *)
      let fv = eval (Lazy.force f.body) in
      (* Here, the physical link is reestablished, but it is important to note
         that the computation of evaluation is done above. So the part below
         only takes a linear time in the size of the normal form of the body
         of the abstraction. *)
      Abst(let rec g = {f with body = lazy (subst_var f fv (BVar(g)))} in g)
  | _         ->
      t

let _ = Printf.printf "id         = %a\n%!" print id
let _ = Printf.printf "eval id    = %a\n%!" print (eval id)

let _ = Printf.printf "idid       = %a\n%!" print idid
let _ = Printf.printf "eval idid  = %a\n%!" print (eval idid)

let _ = Printf.printf "delta      = %a\n%!" print delta
let _ = Printf.printf "eval delta = %a\n%!" print (eval delta)

let _ = Printf.printf "omega      = %a\n%!" print omega
(* The following obviously loops. *)
(*let _ = Printf.printf "eval omega = %a\n%!" print (eval omega)*)

let _ = Printf.printf "weird      = %a\n%!" print weird
let _ = Printf.printf "eval weird = %a\n%!" print (eval weird)

(* Output produced:
id         = λx.x
eval id    = λx.x
idid       = (λx.x) λx.x
eval idid  = λx.x
delta      = λx.(x) x
eval delta = λx.(x) x
omega      = (λx.(x) x) λx.(x) x
weird      = (λx.x) λy.(λx.(x) x) (C) y
eval weird = λy.((C) y) (C) y
*)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.