लिस्प में उद्धरण के बारे में अभी भी

मैं लिस्प में एक नौसिखिया हूं, धीरे-धीरे खाली समय पर सीख रहा हूं ... महीने पहले, मुझे लिस्प आरईपीएल की त्रुटि रिपोर्ट से परेशान था कि निम्नलिखित अभिव्यक्ति काम नहीं करती है:

((if (> 2 1) + -) 1 2)

चारों ओर देखकर मुझे पता था कि लिस्प योजना नहीं है ... लिस्प में, मुझे या तो करने की ज़रूरत है:

(funcall (if (> 2 1) '+ '-) 2 1), or

(funcall (if (> 2 1) #'+ #'-) 2 1)

मैंने lisp-1 और lisp-2 के बारे में प्रारंभिक सामग्री की एक झलक भी ली, हालांकि मैं वहां पूरी सामग्री को बेकार करने में सक्षम नहीं था ... किसी भी मामले में, मुझे पता था कि quote मूल्यांकन को रोकता है, जैसा कि मूल्यांकन नियम के लिए एक अपवाद।

हाल ही में मैं कम ... और फिर एक अभ्यास के रूप में कुछ पढ़ रहा हूं, मैं अपना खुद का संस्करण कम करना चाहता था। हालांकि मैं इसे काम करने में कामयाब रहा (कम से कम यह काम करता प्रतीत होता है), मुझे एहसास हुआ कि मैं अभी भी समझा नहीं सकता कि क्यों, defun के शरीर में, कुछ स्थानों funcall है जरूरत है, और कुछ स्थानों पर नहीं।

Elisp में निम्नलिखित myreduce है:

    (defun myreduce (fn v lst)
    (cond ((null lst) v)
          ((atom lst) (funcall fn v lst))
          (t (funcall fn (car lst) (myreduce fn v (cdr lst))))))

(myreduce '+ 0 '(1 2 3 4))

मेरे प्रश्न तीसरे और चौथी पंक्तियों के बारे में हैं:

  1. तीसरी पंक्ति: मुझे funcall क्यों चाहिए? क्यों न केवल (fn v lst) ? मेरा "तर्क" यह है कि (fn v lst) में, fn सूची में पहला तत्व है, इसलिए lisp इस स्थिति की जानकारी का उपयोग करने के लिए इसका उपयोग करने में सक्षम हो सकता है एक समारोह ... लेकिन यह नहीं है। तो निश्चित रूप से मैं यहाँ कुछ याद किया।

  2. myreduce के रिकर्सिव कॉल में चौथी पंक्ति: fn को किस प्रकार का myreduce पर रिकर्सिव कॉल पर पास किया जा सकता है? '+ या + , या कुछ और?

मुझे लगता है कि कुछ बहुत मौलिक होना चाहिए मुझे पता नहीं है ... मैं जानना चाहता था, जब मैं 6 वीं/आखिरी पंक्ति में दिखाया गया था, तो मैं myreduce कहता हूं, वास्तव में बाद में क्या हो रहा है (कम से कम '+ कैसे पास हो जाता है), और क्या किसी भी आरईपीएल पर्यावरण में इसका पता लगाने का कोई तरीका है?

बहुत बहुत धन्यवाद,

/ BRUIN

0
उपयोग करने के लिए TRACE का उपयोग करने के लिए।
जोड़ा लेखक Rainer Joswig, स्रोत

2 उत्तर

कॉमन लिस्प एक एलआईएसपी -2 है और इसमें दो नामस्थान हैं। कार्यों के लिए एक और चर के लिए एक। तर्क वेरिएबल नेमस्पेस में बाध्य हैं, इसलिए फ़ंक्शन नेमस्पेस में fn मौजूद नहीं है।

(fn arg) ; call what fn is in the function namespace
(funcall fn ...) ; call a function referenced as a variable

'+ is a symbol and funcall and apply will look it up in the global function namespace when it sees it's a symbol instead of a function object. #'+ is an abbreviation for (function +) which resolves the function from the local function namespace. With lots of calls #'+ is faster than '+ since '+ needs a lookup. Both symbol and a function can be passed as fn to myreduce and whatever was passed is the same that gets passed in line 4.

(myreduce '+ 0 '(1 2 3 4)) ; here funcall might lookup what '+ is every time (CLISP does it while SBLC caches it)
(myreduce #'+ 0 '(1 2 3 4)); here funcall will be given a function object looked up in the first call in all consecutive calls

अब यदि आप '+ पास करते हैं तो इसका मूल्यांकन + और एफएन से किया जाएगा। myreduce में हम रिकर्सन में fn पास करते हैं और इसका मूल्यांकन + पर भी किया जाएगा।

# '+ के लिए यह फ़ंक्शन का मूल्यांकन करता है और fn से जुड़ा होता है। myreduce में हम रिकर्सन में fn पास करते हैं और फ़ंक्शन ऑब्जेक्ट का मूल्यांकन किया जाएगा fn वेरिएबल नेमस्पेस में बाध्य था।

सामान्य लिस्प ने फ़ंक्शन नेमस्पेस में जोड़ने के लिए निर्माण किया है। उदाहरण के लिए।

(flet ((double (x) (+ x x))) ; make double in the function namespace
  (double 10)) ; ==> 20

लेकिन आप इसे लिख सकते थे और इसे वैरिएबल नेमस्पेस पर इस्तेमाल कर सकते थे:

(let ((double #'(lambda (x) (+ x x)))) ; make double in the variable namespace
  (funcall double 10))
0
जोड़ा
@ जोशुआ टेलर यह ओपी से कम लेकिन myreduce नहीं था। साथ ही, symbolp होने पर पास कोड को narrowp को ठीक करना संभव है, लेकिन यह प्रोग्रामर के इरादे को तोड़ सकता है। शायद समारोह आत्म-mutates? वैश्विक परिभाषा प्राप्त करने के लिए प्रोग्रामर को एक char जोड़ने और # '+ या शायद (प्रतीक-फ़ंक्शन' +) भेजने के लिए चुनना बहुत आसान है।
जोड़ा लेखक Sylwester, स्रोत
@ जोशुआ टेलर अच्छा उदाहरण। दूसरी ओर क्लाइस्ट। map / कम करें के साथ कैश नहीं करता है। ऐसा लगता है कि हम भविष्यवाणी नहीं कर सकते कि यह कैसे काम करेगा, funcall के विपरीत, यह तब नहीं कहता है जब किसी प्रतीक को एक प्रतीक के लिए मजबूर किया जाता है, तो यह टीसीओ की तरह होगा; कार्यान्वयन निर्भर।
जोड़ा लेखक Sylwester, स्रोत
@ जोशुआ टेलर यह बहुत दिलचस्प है .. हालांकि मैं एसबीसीएल कैशिंग केवल सीएल उच्च आदेश कार्यों पर लागू होता हूं, लेकिन वास्तव में यह myreduce में भी करता है .. भले ही myreduce तार्किक रूप से पास हो अगले पुनरावृत्ति पर केवल एक प्रतीक। मैं will को शायद में बदल दूंगा, लेकिन सीएलआईएसपी कैश नहीं करता है इसका मतलब है कि आप इस पर निर्भर नहीं हो सकते हैं।
जोड़ा लेखक Sylwester, स्रोत
दावा के लिए औचित्य क्या है कि "('+ 0' (1 2 3 4) को कम करें) " funcall देखेंगे कि + हर बार क्या होता है "? कम क्यों नहीं हो सका को के रूप में कार्यान्वित किया जाना चाहिए (कम करें (एफएन-डिज़ाइनर ...) (चलो ((एफएन (नामित-फ़ंक्शन एफएन-डिज़ाइनर)) ... केवल एफएन का उपयोग करें, एफएन-डिज़ाइनर नहीं ... )) ? मैं वास्तव में अपेक्षा करता हूं केवल कार्यान्वित फ़ंक्शन एक बार को देखने के लिए कार्यान्वयन और परिणाम कैश करने के लिए (लेकिन मैं दावा नहीं कर रहा हूं यह वास्तव में, क्या होता है)।
जोड़ा लेखक Joshua Taylor, स्रोत
मैंने बस एसबीसीएल स्रोत पर एक नज़र डाली, और ऐसा नहीं लगता कि यह अनुकूलन बनाया गया है, लेकिन मैं नहीं देख सकता कि यह कहां से प्रतिबंधित होगा।, या तो ...
जोड़ा लेखक Joshua Taylor, स्रोत
यदि यह संभव है, तो प्रोग्रामर जिसका इरादा है कि पुनरावृत्ति के दौरान किसी प्रतीक की फ़ंक्शन परिभाषा को बदलना एक विशेष व्यवहार होगा, कुछ अपरिभाषित व्यवहार के आधार पर भविष्य में कार्यान्वयन अनुकूलन शायद टूट जाएंगे। मैं प्रोग्रामर को दोष दूंगा। :)
जोड़ा लेखक Joshua Taylor, स्रोत
कल्पना आमतौर पर इन कार्यों के बारे में बात करती है ( map [ car, can। ...] , लागू करें , आदि को कम करें) जो फ़ंक्शन डिज़ाइनर लेते हैं भाषा में जो कहता है कि फ़ंक्शन डिज़ाइनर a फ़ंक्शन निर्दिष्ट करता है, और वह फ़ंक्शन कहलाता है, और इसी तरह। (अंतर्निहित) धारणा है कि एक फ़ंक्शन डिज़ाइनर एक फ़ंक्शन को नामित करता है यदि कोई प्रोग्रामर पुनरावृत्ति के दौरान फ़ंक्शन डिज़ाइनर के रूप में उपयोग किए गए प्रतीक के प्रतीक फ़ंक्शन को बदलने पर निर्भर करता है।
जोड़ा लेखक Joshua Taylor, स्रोत
दरअसल, जब मैंने देखा कि कोड कैशिंग कर रहा प्रतीत नहीं होता है, ऐसा लगता है कि इसके बीच कुछ होना चाहिए। उदाहरण के लिए, यह कोड और एसबीसीएल से आउटपुट देखें। फ़ंक्शन स्पष्ट रूप से mapcar और को कम करें दोनों में कैश किया जा रहा है।
जोड़ा लेखक Joshua Taylor, स्रोत
ठीक है, 1.4.1.5 डिज़ाइनर कहते हैं: "अन्यथा ध्यान दिए जाने के अलावा, ऐसी परिस्थिति में जहां निर्दिष्ट वस्तु का उपयोग कई बार किया जा सकता है, यह कार्यान्वयन-निर्भर है कि ऑब्जेक्ट केवल एक बार या फिर ऑब्जेक्ट का उपयोग होने पर जबरदस्त होता है या नहीं। उदाहरण के लिए, मैपकार को एक फ़ंक्शन डिज़ाइनर को तर्क के रूप में प्राप्त होता है, और इसका विवरण लिखा गया है कि यह केवल एक कार्य था। असल में, यह कार्यान्वयन-निर्भर है कि फ़ंक्शन डिज़ाइनर को तुरंत हटाया गया है या फिर इसे चारों ओर ले जाया गया है या न
जोड़ा लेखक Joshua Taylor, स्रोत
... आंतरिक रूप से इस रूप में कि इसे एक तर्क के रूप में दिया गया था और हर बार इसकी आवश्यकता होने पर फिर से सह-संयोजित किया गया था। ज्यादातर मामलों में, अनुरूप कार्यक्रमों में भेद का पता नहीं लगाया जा सकता है, लेकिन कुछ रोगजनक स्थितियां हैं (विशेष रूप से उनमें स्वयं-परिभाषा या पारस्परिक रूप से परिभाषित कार्य शामिल हैं) जो अनुरूप हैं और जो इस अंतर का पता लगा सकते हैं। "पृष्ठ एक उदाहरण दिखाने के लिए चला गया है एक फ़ंक्शन <कोड> ऐड-कुछ स्वयं को फिर से परिभाषित करता है, और वह (मैपकार 'एड-कुछ' (1 2 3 4)) फ़ंक्शन कैश किए जाने के आधार पर अलग-अलग परिणाम लौटा सकता है या नहीं।
जोड़ा लेखक Joshua Taylor, स्रोत
किसी भी दर पर, बिंदु को व्यवस्थित करना था कि (myreduce '+ 0' (1 2 3 4)) में टिप्पणी; यहां funcall देखेंगे कि 'हर बार सटीक है या नहीं। स्पेक का कहना है कि एक कार्यान्वयन में हर बार इसे देखने का विकल्प होता है, और इसे एक बार देखने का विकल्प होता है। कम से कम एक कार्यान्वयन (एसबीसीएल) इसे एक बार देखता है, और मूल्य को कैश करता है। इसलिए funcall देखेंगे कि 'i हर बार कुछ कार्यान्वयन में सत्य हो सकता है, यह सामान्य लिस्प के सामान्य में सत्य नहीं है।
जोड़ा लेखक Joshua Taylor, स्रोत
हाँ, मैंने इस पर अधिक समय बिताया कि मेरा वास्तव में मतलब था, लेकिन यह है उन दिलचस्प किनारों में से एक है जो जानना मजेदार है।
जोड़ा लेखक Joshua Taylor, स्रोत

कॉमन लिस्प में दो (वास्तव में दो से अधिक) नामस्थान हैं: एक चर के लिए और एक कार्यों के लिए। इसका मतलब है कि एक नाम संदर्भ के आधार पर अलग-अलग चीजों का मतलब हो सकता है: यह एक चर हो सकता है और यह एक फ़ंक्शन नाम हो सकता है।

(let ((foo 42))    ; a variable FOO
  (flet ((foo (n) (+ n 107)))   ; a function FOO
    (foo foo)))    ; calling function FOO with the value of the variable FOO

कुछ उदाहरणों को कैसे चर परिभाषित किया जाता है:

(defun foo (n) ...)   ; n is a variable
(let ((n 3)) ...)     ; n is a variable
(defparameter *n* 41) ; *n* is a variable

इसलिए जब भी एक चर परिभाषित और प्रयोग किया जाता है, तो नाम परिवर्तनीय नामस्थान में होता है।

कार्य परिभाषित किए गए हैं:

 (defun foo (n) ...)         ; FOO is a function
 (flet ((foo (n) ...)) ...)  ; FOO is a function

इसलिए जब भी कोई फ़ंक्शन परिभाषित और उपयोग किया जाता है, तो नाम फ़ंक्शन नेमस्पेस में होता है।

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

  (let ((plus (function plus)))
    (funcall plus 10 11)) 

अब वे जैसी चीजें क्यों हैं? ;-)

  • दो नामस्थान हमें उन नामों का उपयोग करने की अनुमति देते हैं जो पहले से ही कार्यरत हैं।

उदाहरण: लिस्प -1 में मैं लिख नहीं सकता:

(defun list-me (list) (list list))

सामान्य लिस्प में उपरोक्त कोड के लिए कोई संघर्ष नहीं है।

  • एक अलग फ़ंक्शन नेमस्पेस संकलित कोड को थोड़ा सा सरल बनाता है:

एक कॉल में (foo 42) नाम का नाम केवल अपरिभाषित किया जा सकता है या यह एक कार्य है। एक और विकल्प मौजूद नहीं है। तो रनटाइम पर हमें वास्तव में फंक्शन ऑब्जेक्ट होने के लिए फूड के फ़ंक्शन वैल्यू को कभी भी जांचना नहीं पड़ता है। यदि फूड का फ़ंक्शन वैल्यू है, तो यह फ़ंक्शन ऑब्जेक्ट होना चाहिए। इसका कारण: सामान्य लिस्प में फ़ंक्शन के अलावा किसी अन्य चीज़ के साथ फ़ंक्शन को परिभाषित करना संभव नहीं है।

योजना में आप लिख सकते हैं:

(let ((list 42))
  (list 1 2 3 list))

ऊपर किसी बिंदु पर जांच की आवश्यकता है और परिणामस्वरूप त्रुटि होगी, क्योंकि LIST 42 है, जो एक फ़ंक्शन नहीं है।

कोड के ऊपर सामान्य लिस्प में केवल एक चर LIST परिभाषित करता है, लेकिन फ़ंक्शन LIST अभी भी उपलब्ध है।

0
जोड़ा