लांबा अभिव्यक्ति को तेज करने के लिए कब?


30

प्रश्न: कब, क्या कभी, क्या यह तेज-उद्धरण के लिए उपयोगी है lambda, और कब, क्या कभी, हमें तेज-उद्धरण नहीं करना चाहिए lambda?

लोग lambdaतीन तरीकों से उपयोग करते हैं:

  1. सादा: (lambda (x) x)
  2. उद्धृत किया: '(lambda (x) x)
  3. तेज उद्धृत किया: #'(lambda (x) x)

यह SO थ्रेड तीन प्रकारों पर चर्चा करता है, यह SO थ्रेड बताता है कि क्यों नहीं उद्धृत किया जाता है (NB: sharp-quote ) नहीं है lambda, और यह SO थ्रेड उद्धृत और तीक्ष्ण-उद्धरण के बीच के भेदों पर भी चर्चा करता है।

अब, अनाम कार्यों पर मैनुअल नोड और lambdaध्यान दें कि lambdaस्व-उद्धरण हैं के लिए docstring :

फॉर्म की एक कॉल (lambda ARGS DOCSTRING INTERACTIVE BODY)स्व-उद्धरण है; लैम्ब्डा अभिव्यक्ति का मूल्यांकन करने का परिणाम अभिव्यक्ति ही है। मेमने की अभिव्यक्ति तब एक समारोह के रूप में माना जा सकता है ...

तो, यह प्रतीत होता है कि (lambda (x) x)और #'(lambda (x) x)समतुल्य हैं, लेकिन '(lambda (x) x)सबसे महत्वपूर्ण नहीं है (जब बाइट-संकलन)।

ऐसा लगता है कि शायद ही कभी चाहेगा बोली एक lambdaहै, लेकिन यह मेरे लिए स्पष्ट नहीं है जब, अगर कभी, हम चाहिए, या नहीं करना चाहिए, तेज बोली:

  • क्या तीक्ष्ण-उद्धृत lambdaकेवल एक शैलीगत विकल्प है, या क्या ऐसी परिस्थितियाँ हैं जिनमें तेज-उद्धरण वास्तव में उपयोगी है?
  • क्या ऐसी परिस्थितियाँ हैं जिनमें हमें तेज-उद्धरण नहीं देना चाहिए lambda, अर्थात ऐसा करने पर कोड का अर्थ बदल जाएगा?

जवाबों:


28

एक बार , लंबोदर के लिए तेज उद्धरण आवश्यक था, अब यह मामला नहीं है।

तो, ऐसा प्रतीत होता है कि (लैम्ब्डा (x) x) और # '(लैम्ब्डा (x) x) समतुल्य हैं, लेकिन' (लैम्ब्डा (x) x) नहीं है (सबसे महत्वपूर्ण बात, जब बाइट-संकलन है)।

हाँ। वास्तव में, पहले दो मूल्यांकन किए जाने पर पूरी तरह समान हैं। जैसा कि आप से जुड़े मैनुअल पेज में वर्णित है :

निम्नलिखित प्रपत्र सभी समतुल्य हैं:

(lambda (x) (* x x)) 
(function (lambda (x) (* x x))) 
#'(lambda (x) (* x x))

दो दशक पहले Emacs संस्करणों का समर्थन करने की कोशिश करने के अलावा, एक लैम्ब्डा को तेज करने का कोई कारण नहीं है।

तो नहीं है।


अलग नोट के रूप में:

  • एक लंबोदर (के साथ ') को उद्धृत करने से फर्क पड़ता है, यह बाइट संकलन को रोकता है। मैं ऐसे परिदृश्य के बारे में नहीं सोच सकता जहाँ यह उपयोगी है, लेकिन कौन जानता है।

  • बैकटिक एकमात्र ऐसा उद्धरण है, जो वास्तव में लंबोदर के साथ उपयोगी है, लेकिन केवल तभी जब आप किसी कारण से शाब्दिक बंधन का उपयोग नहीं कर रहे हैं।


मैनुअल के बेनामी फ़ंक्शंस अनुभाग में एक लिंक जोड़ने पर विचार करें जिसमें एक उदाहरण है जिसमें बाइट संकलन पर उद्धरण के प्रभाव को समझाया गया है।
कांस्टेंटाइन

@ कॉन्सटेंटाइन ने किया। मुझे एक आलसी कारण मिला, मैं एक फोन पर हूं, और ओपी ने पहले ही इसे वैसे भी लिंक कर दिया है।
मालाबार

क्या आप स्पष्ट कर सकते हैं कि लेसिक बाइंडिंग और बैकटिक का उपयोग न करने के बारे में आपका क्या मतलब है? धन्यवाद।
coredump

@coredump डायनेमिक बाइंडिंग के साथ, एक लैम्ब्डा के अंदर बाहरी वेरिएबल्स को एक्सेस करने का एकमात्र तरीका है लैम्बडा को मैन्युअल रूप से वेरिएबल के साथ लिस्ट के रूप में बनाना। बैकटिक्स उस तरह के लिए अच्छे हैं।
मालाबार

BTW, मुझे नहीं लगता कि "एक समय पर एक बार" वास्तव में लागू होता है: जब मैंने संशोधन इतिहास में इस विषय की जांच की, तो मैंने पाया कि lambdaइसे एक मैक्रो के रूप में परिभाषित किया गया है, जो functionमुझे वापस जाने के लिए जोड़ता है । IOW अगर #'किसी बिंदु पर आवश्यक हो गया है, तो यह बहुत प्रारंभिक विकास कोड में था। यह निश्चित रूप से Emacs-18 में पहले से ही आवश्यक नहीं था।
स्टीफन

5

चूंकि lambdaइसका कोई मतलब नहीं है, जब इसे उद्धृत नहीं किया जाता है, हाल ही के Emacs Lisp का अनुसरण करने वाले संस्करण (ANSI) सामान्य लिस्प के रूप में निर्विवाद (lambda...)रूप से व्याख्या करते हैं #'(lambda...)। दो संकेतन लगभग बिल्कुल समतुल्य हैं (उद्धृत संरचना को छोड़कर)।

पसंद करना है (lambda...)या #'(lambda...)इसलिए विशुद्ध रूप से शैली की बात है। कुछ लोग नग्न रूप पसंद करते हैं, जो वाक्यात्मक शोर से बचते हैं, जबकि अन्य (स्वयं सहित) उद्धृत रूप को पसंद करते हैं।


यह क्विक मैनुअल का विरोधाभास करता है: "एमएसीएस लिस्प में, ऐसी सूची एक वैध अभिव्यक्ति है जो एक फ़ंक्शन ऑब्जेक्ट का मूल्यांकन करती है।"
djechlin

8
"हाल के संस्करण" जैसा कि "संस्करण 1990 या उसके बाद जारी किए गए" ;-)
स्टीफ़न

0

अतिरिक्त इतिहास के एक बिट को जोड़ने, देखने के कारण # '(लंबो ...) ऐतिहासिक विरासत है?

https://debbugs.gnu.org/cgi/bugreport.cgi?bug=4290 से पता चलता है कि:

Emacs 22 से शुरू होकर, एक lambdaफॉर्म को बाइट-संकलित किया जाता है, जब इसे फ़ंक्शन के रूप में उपयोग किया जाता है, भले ही यह पहले से हो functionया नहीं #'। 22 से पहले Emacs संस्करणों के साथ, आपको स्पष्ट रूप से उपयोग करना चाहिए #' या functionयदि आप चाहते हैं कि फॉर्म बाइट संकलित हो।

मैं बाइट-कंपाइलर के बारे में नहीं जानता, लेकिन मैं यह देख सकता हूं कि 1993 में कम से कम lambdaमैक्रो ने ही एक (function (lambda ...))फॉर्म वापस किया था ।

https://www.iro.umontreal.ca/~monnier/hopl-4-emacs-lisp.pdf भी कहता है:

दिलचस्प है कि (MacLisp के विपरीत), lambda1991 के आसपास तक तकनीकी रूप से एलिस्प भाषा का हिस्सा नहीं था , जब इसे एमएसीएस -19 के विकास के दौरान एक मैक्रो के रूप में जोड़ा गया था। Emacs-18 में, अनाम कार्यों को फ़ॉर्म के उद्धृत मूल्यों के रूप में लिखा गया था:

'(lambda (..ARGS..) ..BODY..)

जबकि lambdaमैक्रो ने इस उद्धरण को लगभग 30 वर्षों के लिए अनावश्यक बना दिया है, इस अभ्यास के कई उदाहरण अभी भी एलिस्प कोड में होते हैं, भले ही यह शरीर के बाइट-संकलन को रोकता है। कुछ हद तक केवल 1993 में, लूसिड इमाक्स ने 19.8 में मैकलिस्प से #'...पाठक शॉर्टहैंड का आयात किया (function ...)। Emacs ने इसके बाद साल के दौरान सूट किया।


0

बस बैकटिक लैम्ब्डा अभिव्यक्ति का उपयोग करने का एक व्यावहारिक उदाहरण देना चाहते हैं। यह लेक्सिकल-बाइंडिंग / वैरिएबल शैडोइंग के बारे में है, बैकटिक लैम्ब्डा एक्सप्रेशन का उपयोग करते हुए और कॉमा के साथ वेरिएबल्स को संदर्भित करते हुए उनके वैश्विक मूल्य को प्राप्त करना संभव बनाता है।

;; -*- lexical-binding:t -*-
(let ((my-variable "Random old"))
  (funcall `(lambda()
             (let ((my-variable "Random"))
               (message ,my-variable)))))

M-x [RET] eval-buffer आउटपुट "रैंडम पुराना"

;; -*- lexical-binding:t -*-
(let ((my-variable "Random old"))
  (funcall (lambda()
             (let ((my-variable "Random"))
               (message my-variable)))))

M-x [RET] eval-buffer आउटपुट "रैंडम"

वैश्विक चर और चर के स्थानीय चर को मिलाकर एक तीसरा उदाहरण

;; -*- lexical-binding:t -*-
(let ((my-variable "Random old"))
  (funcall `(lambda()
              (let ((my-variable "Random"))
                (message my-variable)
                (message ,my-variable)))))

M-x [RET] eval-buffer आउटपुट "रैंडम" "रैंडम पुराना"


@npostavs जो मेरे उदाहरण के साथ बात नहीं थी लेकिन मैंने उस बुरे अभ्यास से बचने के लिए अपने उदाहरण को संशोधित किया
cjohansson

बेहतर, हालांकि मैं अभी भी आश्वस्त नहीं हूं कि यह केवल आंतरिक बंधन के लिए एक अलग नाम चुनने पर सुधार है।
npostavs
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.