2010-02-19 16 views
36

क्या कोई ऐसे लेख सुझा सकता है जो Homoiconicity की अवधारणा को समझाता है, विशेष रूप से क्लोजर का उपयोग करना। यह क्यों है कि क्लोजर होम्योनिक है लेकिन जावा जैसी अन्य भाषाओं में ऐसा करना मुश्किल है?Homoiconicity, यह कैसे काम करता है?

+0

Homoiconicity बुलाया में अधिक बड़े पैमाने पर इस बारे में लिखा था एक ऐसी विशेषता है जो भाषा नहीं हो सकता है हो सकता है या है, लेकिन यह कुछ तुम (एक नई भाषा बनाने के बिना) जोड़ सकते हैं नहीं है। जावा में करना मुश्किल नहीं है - जावा बस होमियोइकोनिक नहीं है (यह हेटरोइकोनिक है)। यह कारों के समान ही है - आप सुबारू इंप्रेज़ा को संशोधित कर सकते हैं ताकि यह राक्षस ट्रक बन जाए; लेकिन यह राक्षस ट्रक नहीं है, और परिणामी कार अब subaru impreza नहीं है। – MatthewRock

उत्तर

22

इससे पहले कि मैं कुछ चीजों के साथ आगे बढ़ूं, मैं एक और संदर्भ जोड़ना चाहता हूं, यहां एक और संदर्भ है - होम्योनोनिसिटी से संबंधित हिस्सा काफी छोटा है, लेकिन यह समृद्ध हिकी समझा रहा है! चैनल 9 में this nice video रिच हिकी और ब्रायन बेकमैन क्लोजर के बारे में बात कर रहे हैं। Concurrency, समझदारी से, प्रमुख फोकस है, लेकिन Homoiconicity स्क्रीन समय का अपना (छोटा) पल प्राप्त करता है जिसके दौरान अमीर read के बीच इंटरप्ले को स्पष्ट रूप से समझाता है (यह फ़ंक्शन प्रोग्रामर द्वारा लिखित आंतरिक प्रतिनिधित्व के लिए लिखित कंक्रीट वाक्यविन्यास को परिवर्तित करता है सूचियों आदि से) और eval। उनके पास यह अच्छा आरेख है कि eval कभी भी यह नहीं जानता कि उसका मूल्यांकन करने वाला कोड read से एक टेक्स्ट फ़ाइल पर काम कर रहा है ... आर्थर ने पहले ही इसके बारे में जानकारी दी है, लेकिन हे, इसे वैसे भी देखें, यह एक बहुत अच्छा वीडियो है!


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


मैं अपने प्रश्न के दूसरे भाग को संबोधित करना चाहते हैं - कैसे यह है कि ज्यादातर प्रोग्रामिंग भाषाओं homoiconic नहीं माना जाता है? मुझे इस प्रक्रिया में लिस्प के अर्थशास्त्र पर छूना होगा, लेकिन चूंकि निल्स ने पहले से ही "होमियोइकोनिक" शब्द पर जानकारी के अच्छे स्रोतों के लिंक दिए हैं और आर्थर ने पढ़ा है -> मैक्रो विस्तार -> संकलन चक्र जैसा पाया गया है क्लोजर में, मैं उस पर निर्माण करूँगा जो निम्नानुसार है। बातें शुरू करने के लिए, मुझे एलन Kay के एक भाग में (विकिपीडिया लेख जो भी मूल स्रोत के लिए लिंक से निकाले) बोली जाने:

[...] इंटरएक्टिव लिस्प [...] और TRAC [। ..] दोनों "homoiconic" हैं कि उनके आंतरिक और बाहरी प्रतिनिधित्व अनिवार्य रूप से वही हैं।

(उन [...] बिट्स पाठ का एक बहुत छुपाने के लिए, लेकिन सार अपरिवर्तित है।)

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

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

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

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

बेशक एक बार भाषा को एएसटी के समानांतर नोटेशन में लिखा जाता है और एक मूल्यांकनकर्ता कार्य/वस्तु के साथ लिस्प-जैसे निष्पादन मॉडल का उपयोग करता है, तो किसी को यह आश्चर्य करना चाहिए कि यह किसी भी मौके से लिस्प की दूसरी बोली नहीं है .. यहां तक ​​कि यदि इसका एएसटी-समांतर वाक्यविन्यास एक्सएमएल-आधारित होता है। shudder

1

यह लगभग स्पष्ट करने के लिए हो रहा है, लेकिन पहले स्रोतों हो सकता है:

http://en.wikipedia.org/wiki/Homoiconicity

http://c2.com/cgi/wiki?DefinitionOfHomoiconic

Homoiconicity सामान्य से समझाया गया है और आप भी जन्म लिया स्रोतों पा सकते हैं। जैसा कि लिस्प के उदाहरण का उपयोग करके समझाया गया है, यह क्लोजर से बहुत दूर नहीं है।

+0

तो यदि मैं जावा में विकिपीडिया उदाहरण का प्रयास करता हूं। 1. एक जावा प्रोग्राम में एक वर्ग स्ट्रिंग वाला वर्ग होता है जो स्वयं जावा कार्यक्रम है। (ठीक से बच निकला) 2. सीओएस से एसआईएन पर किसी ऑब्जेक्ट को प्रतिस्थापित करने के लिए रेगेक्स का उपयोग करके इसे मैनिपुलेट करें 3. बाहरी प्रोग्राम (एक जावा कंपाइलर) को कॉल करें जो ऊपर दिए गए संशोधित स्ट्रिंग को निष्पादित करेगा फ़ाइल। 4. आउटपुट उस कार्यक्रम का निष्पादन होगा जो मूल वर्ग में एक स्ट्रिंग था। 5. आप स्ट्रिंग फ़ील्ड को मूल वर्ग की मुख्य विधि में इनपुट के रूप में भी ले सकते हैं। तो क्या यह दर्शाता है कि जावा होमियोइकोनिक भी है? –

+0

निश्चित रूप से जावा में क्लास फाइलों का बाइटकोड प्रतिनिधित्व जावा कोड के लिए सिंटैक्स के समान नहीं है ... –

+0

पहले मामले में जोड़ने के लिए, मेरे पास क्लासलोडर उपर्युक्त प्रोग्राम के संकलन के बाद उत्पन्न कक्षा फ़ाइलों को लोड करेगा और प्रतिबिंब का उपयोग करेगा नए भारित वर्गों पर विधियों को निष्पादित करें। –

6

जब मैं homoiconicity की लिस्प विचार भावना बनाया जब मुझे पता चला कि तुतलाना "संकलित" है दो चरणों में, पढ़ने और संकलन और कोड इन दोनों के लिए एक ही डेटा संरचना के साथ प्रस्तुत किया जाता है तैयार कर रही थी:

  • पहले आप अपने सिर
  • में एक स-अभिव्यक्ति के बारे में सोच तो आप एक फ़ाइल
  • में पात्रों के रूप में एस अभिव्यक्ति टाइप करें और उसके पाठक एस भाव में फ़ाइल में पात्रों अनुवाद करता है। यह कार्यक्रम को संकलित नहीं कर रहा है, सिर्फ वर्णों से डेटा संरचनाओं का निर्माण करना यह पठन चरण का हिस्सा है।
  • तो पाठक प्रत्येक अभिव्यक्ति को देखता है और फैसला करता है कि वे एक मैक्रो हैं और यदि ऐसा है तो मैक्रो को एक और एस-अभिव्यक्ति उत्पन्न करने के लिए चलाता है। इसलिए इस बिंदु पर हम एस-एक्सप्रेशन से पात्रों तक एस-एक्सप्रेशन तक चले गए हैं, फिर एस-एक्सप्रेशन से विभिन्न एस-एक्सप्रेशन तक।
  • इन एस-एक्सप्रेशन को तब .class फ़ाइलों में संकलित किया जाता है जिन्हें जेवीएम द्वारा चलाया जा सकता है यह "संकलन" चरण का दूसरा भाग है।

तो यह आपके मस्तिष्क से .class फ़ाइल तक सभी तरह से बहुत अधिक अभिव्यक्ति करता है। आप एस-एक्सप्रेशन लिखते हैं जो एस-एक्सप्रेशन लिखते हैं। इसलिए आप कह सकते हैं कि "कोड डेटा है" या "कोड डेटा है" क्योंकि यह बेहतर लगता है।

+1

वास्तव में यह भ्रामक है कि पाठक के अंदर मैक्रो विस्तार होता है।ध्यान दें कि कैसे '(eval' (जब सत्य (println: foo) (println: bar))) 'अपेक्षित के रूप में काम करता है, भले ही पाठक स्पष्ट रूप से उद्धृत सूची संरचना '' को जोड़ नहीं सकता है (जब सत्य (println: foo) (println : बार)) '। मानक नामकरण पढ़ने के समय (चरित्र धारा -> डेटा संरचना रूपांतरण) और मैक्रो विस्तार समय (डेटा संरचना परिवर्तन) के बीच भी अंतर करता है। तथ्य यह है कि संकलन से पहले मैक्रो विस्तार होता है, हालांकि, मैक्रोज़ को समझने का मुख्य बिंदु कौन सा है। –

+0

इसे इंगित करने के लिए धन्यवाद। मैंने पाठक का हिस्सा होने के बारे में टिप्पणी हटा दी। –

+0

पाठक वर्णों को एस-एक्सप्रेशन में अनुवाद नहीं करता है। पाठक डेटा में एस-एक्सप्रेशन का अनुवाद करता है। –

4

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

लिस्प और कई अन्य प्रोग्रामिंग भाषाओं के बीच मुख्य अंतर यह है कि लिस्प के पास स्रोत कोड के लिए एक सरल डेटा प्रतिनिधित्व है - जो तारों पर आधारित नहीं है।

स्पष्ट रूप से कोड को पाठ-आधारित प्रोग्रामिंग भाषाओं में स्ट्रिंग के रूप में दर्शाया जा सकता है। लेकिन लिस्प में स्रोत को प्राचीन लिस्प डेटा संरचनाओं के संदर्भ में प्रदर्शित किया जा सकता है। बाहरी प्रतिनिधित्व एस-एक्सप्रेशन पर आधारित है, जो पाठ के रूप में पदानुक्रमित डेटा का प्रतिनिधित्व करने के लिए एक साधारण मॉडल है। आंतरिक मॉडल प्रतिनिधित्व सूचियों पर आधारित है, आदि

मूल्यांकनकर्ता को यही मिलता है: आंतरिक प्रतिनिधित्व। पाठ इनपुट के 1 से 1 संस्करण नहीं, लेकिन पार्स किया गया।

बुनियादी मॉडल:

  • पढ़ें तब्दील डेटा में बाहरी एस भाव
  • EVAL लिस्प डेटा के रूप में लिस्प रूपों लेता है और उन्हें मूल्यांकन करता
  • प्रिंट बाहरी एस भाव में लिस्प डेटा तब्दील

ध्यान दें कि मनमाने ढंग से लिस्प डेटा के लिए पढ़ें और प्रिंट करें, जिसमें एक मुद्रित प्रतिनिधित्व और पाठक है, न केवल लिस्प के रूपों के लिए। फॉर्म लिस्प प्रोग्रामिंग भाषा में परिभाषा मान्य अभिव्यक्तियों के अनुसार हैं।

3

प्रतीकात्मक भेदभाव करने के लिए यहां एक छोटा कार्यक्रम है। यह एलआईएसपी का अपना उदाहरण है जो अपना कोड जोड़ता है। यह देखने के लिए कि किसी अन्य चीज़ के लिए LISP अच्छा क्यों है, इसे दूसरी भाषा में अनुवाद करने का प्रयास करें।

;; The simplest possible symbolic differentiator 

;; Functions to create and unpack additions like (+ 1 2) 
(defn make-add [ a b ] (list '+ a b)) 
(defn addition? [x] (and (=(count x) 3) (= (first x) '+))) 
(defn add1 [x] (second x)) 
(defn add2 [x] (second (rest x))) 

;; Similar for multiplications (* 1 2) 
(defn make-mul [ a b ] (list '* a b)) 
(defn multiplication? [x] (and (=(count x) 3) (= (first x) '*))) 
(defn mul1 [x] (second x)) 
(defn mul2 [x] (second (rest x))) 

;; Differentiation. 
(defn deriv [exp var] 
    (cond (number? exp) 0                ;; d/dx c -> 0 
     (symbol? exp) (if (= exp var) 1 0)           ;; d/dx x -> 1, d/dx y -> 0 
     (addition? exp) (make-add (deriv (add1 exp) var) (deriv (add2 exp) var))  ;; d/dx a+b -> d/dx a + d/dx b 
     (multiplication? exp) (make-add (make-mul (deriv (mul1 exp) var) (mul2 exp)) ;; d/dx a*b -> d/dx a * b + a * d/dx b 
             (make-mul (mul1 exp) (deriv (mul2 exp) var))) 
     :else :error)) 

;;an example of use: create the function x -> x^3 + 2x^2 + 1 and its derivative 
(def poly '(+ (+ (* x (* x x)) (* 2 (* x x))) 1)) 

(defn poly->fnform [poly] (list 'fn '[x] poly)) 

(def polyfn (eval (poly->fnform poly))) 
(def dpolyfn (eval (poly->fnform (deriv poly 'x)))) 
+0

क्या आप इसे थोड़ा और समझाएंगे? – Ali

+0

मैं इस समय थोड़ा व्यस्त हूं, लेकिन यह इससे आया: http://www.learningclojure.com/2010/02/clojure-dojo-4-symbolic-differentiation.html, जो एक श्रृंखला का भाग चार है क्लोजर शुरुआती के लिए 'डोजोस' का। यदि आपको क्लोजर बिट्स नहीं मिलते हैं तो पहले पढ़ने वाले लोगों को मदद मिल सकती है (पता लगाएं कि डोजो पहले क्या है)। यदि गणित समस्या है तो भेदभाव पर एक स्कूल गणित पुस्तक पढ़ें जो उत्पाद नियम तक जाती है। –

0

रेनर Joswig बताते हैं, वहाँ homoiconicity के विचार की उपयोगिता पर शक करने के लिए अच्छा कारण हैं, और Lisps है कि क्या वास्तव में Homoiconic हैं।

पर homoiconiticy केंद्रों की मूल परिभाषा एक भाषा की आंतरिक और बाहरी प्रस्तुतियों के बीच समानता।कैननिकल उदाहरण लिस्प है, इसके एस-एक्सप्रेशन के साथ।

उदाहरण के लिए परिभाषा और पसंद के साथ दो (कम से कम) दो समस्याएं हैं।

पहली आपत्ति बाहरी प्रतिनिधित्व से संबंधित है। लिस्प के मामले में हम मानते हैं कि बाहरी प्रतिनिधित्व एक एस-अभिव्यक्ति है। अधिकांश व्यावहारिक प्रोग्रामिंग वातावरण में, हालांकि, प्रोग्राम स्रोतों का वास्तविक प्रतिनिधित्व टेक्स्ट फाइलों के रूप में होता है जिसमें वर्णों के तार होते हैं। यह इस पाठ को पार्स करने के बाद ही है कि प्रतिनिधित्व वास्तव में एक अभिव्यक्ति है। दूसरे शब्दों में: व्यावहारिक वातावरण में बाहरी प्रतिनिधित्व एक अभिव्यक्ति नहीं है, लेकिन पाठ।

दूसरा आपत्ति आंतरिक प्रतिनिधित्व से संबंधित है। लिस्प दुभाषियों के व्यावहारिक कार्यान्वयन आम तौर पर प्रदर्शन कारणों से आंतरिक रूप से एस-अभिव्यक्तियों पर सीधे काम नहीं करते हैं। भले ही एक लिस्प को एस-एक्सप्रेशन पर केस-विश्लेषण के संदर्भ में परिभाषित किया जा सकता है, लेकिन आमतौर पर इसे लागू नहीं किया जाता है। इस प्रकार, आंतरिक प्रतिनिधित्व वास्तव में अभ्यास में एक एस अभिव्यक्ति नहीं है।

वास्तव में, कोई भी homoiconicity की अवधारणा के आसपास और सवाल उठा सकता है: एक अच्छी तरह से encapsulated मशीन के लिए, हम परिभाषा के द्वारा अपने आंतरिक कार्य का निरीक्षण नहीं कर सकते हैं; उस दृश्य में, मशीन के आंतरिक प्रतिनिधित्व के बारे में कोई कथन बनाना अर्थहीन है। अधिक आम तौर पर, मूल परिभाषा में समस्या होती है कि विचार यह है कि कार्यक्रम का एक बाहरी और एकल आंतरिक प्रतिनिधित्व वास्तविकता से मेल नहीं खाता है। वास्तव में, प्रोग्रामर के मस्तिष्क में इलेक्ट्रॉनों, स्क्रीन से उत्सर्जित फोटॉन, प्रोग्राम टेक्स्ट, मशीन कोड, और सीपीयू में चलने वाले इलेक्ट्रॉनों सहित इलेक्ट्रॉनों समेत प्रतिनिधित्व की एक पूरी श्रृंखला है।

मैं एक लेख Don't say “Homoiconic”

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