python - लिस्प का रीड-इवल-प्रिंट लूप, पायथन से अलग कैसे है?




functional-programming lisp (3)

मैंने रिचर्ड स्टालमैन के एक निम्न कथन का सामना किया है:

'जब आप एक लिस्प प्रणाली शुरू करते हैं, तो यह एक रीड-इवल-प्रिंट लूप में प्रवेश करता है। अधिकांश अन्य भाषाओं में न तो पढ़ने के लिए तुलनीय है, न ही विकसित करने के लिए तुलनीय और प्रिंट करने के लिए तुलनीय कुछ भी नहीं है। क्या कमियों की खाई! '

अब, मैंने लिस्प में बहुत कम प्रोग्रामिंग की, लेकिन मैंने पायथन में कोड की काफी मात्रा लिखी है और हाल ही में एर्लांग में थोड़ी। मेरी धारणा थी कि ये भाषाएं रीड-इवल-प्रिंट लूप भी प्रस्तुत करती हैं, लेकिन स्टालमैन असहमत हैं (कम से कम पायथन के बारे में):

लोगों द्वारा मुझे बताया जाने के बाद कि मैं मूल रूप से लिस्प के समान था, मैंने पायथन के दस्तावेज को स्किम्ड कर दिया। मेरा निष्कर्ष यह है कि ऐसा नहीं है। जब आप लिस्प शुरू करते हैं, तो यह 'रीड', 'ईवैल' और 'प्रिंट' करता है, जो सभी पायथन में गायब हैं। '

क्या वास्तव में लिस्प और पायथन के रीड-इवल-प्रिंट लूप के बीच एक मौलिक तकनीकी अंतर है? क्या आप उन चीजों का उदाहरण दे सकते हैं जो लिस्प आरईपीएल आसान बनाता है और जो पायथन में करना मुश्किल है?


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

आपके पास REPL अवधारणा के दो अलग-अलग अर्थ हो सकते हैं:

  • लिस्प में पढ़ें एवल प्रिंट लूप (या कुछ अन्य समान भाषाएं)। यह कार्यक्रमों और डेटा को पढ़ता है, यह परिणाम डेटा का मूल्यांकन और प्रिंट करता है। अजगर इस तरह से काम नहीं करता है। लिस्प का REPL आपको सीधे मेटा-प्रोग्रामिंग तरीके से काम करने की अनुमति देता है, कोड लिखता है जो (कोड) उत्पन्न करता है, विस्तार की जांच करता है, वास्तविक कोड को रूपांतरित करता है, आदि। लिस्प ने शीर्ष लूप के रूप में पढ़ा / विकसित / प्रिंट किया है। पायथन में टॉप-लूप के रूप में रीडस्ट्रिंग / मूल्यांकन / प्रिंटस्ट्रिंग जैसा कुछ है।

  • कमांड लाइन इंटरफ़ेस। एक इंटरैक्टिव शेल। IPython के लिए उदाहरण के लिए देखें। इसकी तुलना आम लिस्प के SLIME

डिफ़ॉल्ट मोड में अजगर का डिफ़ॉल्ट खोल वास्तव में इंटरैक्टिव उपयोग के लिए शक्तिशाली नहीं है:

Python 2.7.2 (default, Jun 20 2012, 16:23:33) 
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a+2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> 

आपको एक त्रुटि संदेश मिलता है और वह यह है।

इसकी तुलना CLISP REPL से करें:

rjmba:~ joswig$ clisp
  i i i i i i i       ooooo    o        ooooooo   ooooo   ooooo
  I I I I I I I      8     8   8           8     8     o  8    8
  I  \ `+' /  I      8         8           8     8        8    8
   \  `-+-'  /       8         8           8      ooooo   8oooo
    `-__|__-'        8         8           8           8  8
        |            8     o   8           8     o     8  8
  ------+------       ooooo    8oooooo  ooo8ooo   ooooo   8

Welcome to GNU CLISP 2.49 (2010-07-07) <http://clisp.cons.org/>

Copyright (c) Bruno Haible, Michael Stoll 1992, 1993
Copyright (c) Bruno Haible, Marcus Daniels 1994-1997
Copyright (c) Bruno Haible, Pierpaolo Bernardi, Sam Steingold 1998
Copyright (c) Bruno Haible, Sam Steingold 1999-2000
Copyright (c) Sam Steingold, Bruno Haible 2001-2010

Type :h and hit Enter for context help.

[1]> (+ a 2)

*** - SYSTEM::READ-EVAL-PRINT: variable A has no value
The following restarts are available:
USE-VALUE      :R1      Input a value to be used instead of A.
STORE-VALUE    :R2      Input a new value for A.
ABORT          :R3      Abort main loop
Break 1 [2]> 

CLISP एक डीबगर REPL में ब्रेक करने के लिए लिस्प की स्थिति प्रणाली का उपयोग करता है। यह कुछ पुनरारंभ प्रस्तुत करता है। त्रुटि संदर्भ में, नया REPL विस्तारित कमांड प्रदान करता है।

चलो का उपयोग करें :R1 पुनरारंभ:

Break 1 [2]> :r1
Use instead of A> 2
4
[3]> 

इस प्रकार आप कार्यक्रमों और निष्पादन रन की इंटरैक्टिव मरम्मत प्राप्त करते हैं ...


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

अब, कुछ वस्तुएं "अंतर में दयालु" के करीब आती हैं, पायथन कोड फ़ाइल में, आप आसानी से रिक्त लाइनों को सम्मिलित कर सकते हैं:

def foo(n):
  m = n + 1

  return m

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

इसके अलावा, कॉमन लिस्प (सीएल) में कुछ नहीं बल्कि आसान सुविधा वाले वैरिएबल हैं जो पाइथन में उपलब्ध नहीं हैं (कम से कम जहां तक ​​मुझे पता है)। सीएल और पायथन दोनों में "अंतिम अभिव्यक्ति का मूल्य" ( * सीएल में _ , पायथन में) है, लेकिन सीएल में भी ** (अंतिम से पहले अभिव्यक्ति का मूल्य) और *** (उस से पहले एक का मूल्य) और +++ और +++ (स्वयं भाव)। सीएल भी अभिव्यक्तियों और कथनों के बीच अंतर नहीं करता है (संक्षेप में, सब कुछ एक अभिव्यक्ति है) और यह सब बहुत समृद्ध आरईपीएल अनुभव बनाने में मदद करता है।

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


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

कहते हैं कि आप रुचि रखते हैं कि विशेष फार्म कैसे लागू किया जाता है। आप इसे इस तरह से परख सकते हैं:

[4]> (macroexpand '(incf a))
(SETQ A (+ A 1)) ;

लेकिन incf प्रतीक मूल्यों को बढ़ाने से ज्यादा कर सकते हैं। हैश तालिका प्रविष्टि को बढ़ाने के लिए कहने पर वास्तव में यह क्या करता है? चलो देखते हैं:

[2]> (macroexpand '(incf (gethash htable key)))
(LET* ((#:G3069 HTABLE) (#:G3070 KEY) (#:G3071 (+ (GETHASH #:G3069 #:G3070) 1)))
 (SYSTEM::PUTHASH #:G3069 #:G3070 #:G3071)) ;

यहां हम सीखते हैं कि puthash एक सिस्टम-विशिष्ट puthash फ़ंक्शन को कॉल करता है, जो इस कॉमन लिस्प सिस्टम का कार्यान्वयन विवरण है। ध्यान दें कि "प्रिंटर" "रीडर" के लिए ज्ञात विशेषताओं का उपयोग कैसे कर रहा है, जैसे कि #: सिंटैक्स के साथ अनाम प्रतीकों को प्रस्तुत करना और विस्तारित अभिव्यक्ति के दायरे के भीतर समान प्रतीकों का संदर्भ देना। पायथन में इस तरह के निरीक्षण का अनुकरण करना अधिक क्रियात्मक और कम सुलभ होगा।

REPL में स्पष्ट उपयोगों के अलावा, अनुभवी लिस्पर्स XML या json की तुलना में एक सरल और आसानी से उपलब्ध क्रमांकन उपकरण के रूप में print और कोड में read । जबकि पाइथन में str फंक्शन है, जो लिस्प के print के बराबर है, इसमें read के समतुल्य, निकटतम समकक्ष होने का अभाव है। पाठ्यक्रम का निष्कासन दो अलग-अलग अवधारणाओं, पार्सिंग और मूल्यांकन का सामना करता है, जो इस तरह की समस्याओं और समाधान की ओर जाता है और पायथन मंचों पर एक आवर्ती विषय है। यह ठीक लिस्प में एक मुद्दा नहीं होगा क्योंकि पाठक और मूल्यांकनकर्ता सफाई से अलग हैं।

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







read-eval-print-loop