कॉमन लिस्प में `सेट`,` सेटक` और `सेटफ़` के बीच अंतर?


166

कॉमन लिस्प में "सेट", "सेटक" और "सेटफ" के बीच अंतर क्या है?


9
इनका व्यवहार उत्तर में बहुत अच्छी तरह से उत्तर दिया गया है, लेकिन स्वीकार किए गए उत्तर में संभवतः "सेट" में "एफ" के लिए गलत व्युत्पत्ति है। उत्तर क्या है? यह कहता है कि यह "फ़ंक्शन" के लिए है, और इसे वापस करने के लिए संदर्भ प्रदान करता है।
जोशुआ टेलर

जवाबों:


169

मूल रूप से, लिस्प में, कोई शाब्दिक चर नहीं थे - केवल गतिशील वाले। और SETQ या SETF नहीं था, सिर्फ SET फ़ंक्शन था।

अब क्या लिखा है:

(setf (symbol-value '*foo*) 42)

के रूप में लिखा गया था:

(set (quote *foo*) 42)

जो अंततः SETQ (सेट उद्धरण) से अलग हो गया:

(setq *foo* 42)

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

बाद में, किसी ने SETF (SET फील्ड) का आविष्कार डेटा संरचनाओं को मान देने के एक सामान्य तरीके के रूप में किया, अन्य भाषाओं के एल-मूल्यों को प्रतिबिंबित करने के लिए:

x.car := 42;

के रूप में लिखा जाएगा

(setf (car x) 42)

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

फिर प्रतीक मैक्रों हुए। ताकि प्रतीक मैक्रों पारदर्शी रूप से काम कर सकें, यह महसूस किया गया कि SETQ को SETF की तरह कार्य करना होगा यदि "चर" को सौंपा जा रहा है तो वास्तव में एक प्रतीक मैक्रो था:

(defvar *hidden* (cons 42 42))
(define-symbol-macro foo (car *hidden*))

foo => 42

(setq foo 13)

foo => 13

*hidden* => (13 . 42)

इसलिए हम वर्तमान समय में आते हैं: SET और SETQ पुरानी बोलियों के एट्रोफाइड अवशेष हैं, और संभवतः कॉमन लिस्प के अंतिम उत्तराधिकारियों से बूट किए जाएंगे।


45
आम लिस्प में हमेशा शाब्दिक चर होते थे। आप कॉमन लिस्प से पहले कुछ लिस्प के बारे में बात कर रहे होंगे।
रेनर जोस्विग

4
यदि SET और SETQ को एक सामान्य लिस्प उत्तराधिकारी से बूट किया जाना है, तो उन्हें कुछ प्रतिस्थापन प्राप्त करना होगा। उच्च-स्तरीय कोड में उनका उपयोग सीमित है, लेकिन निम्न-स्तरीय कोड (उदाहरण के लिए, SETF कोड लागू किया गया है) की आवश्यकता है।
श्वेन्ते

13
क्या कोई कारण है कि आपने कार के क्षेत्र में 'कार' को एक क्षेत्र के रूप में चुना है जो कार फ़ंक्शन के रूप में भ्रमित हो सकता है?
ड्रूडू

9
इस उत्तर के लिए क्या के लिए setf स्टैंड में च करता है? दावा करता है कि fवास्तव में कार्य के लिए खड़ा है , न कि फ़ील्ड (या फॉर्म , उस मामले के लिए), और संदर्भ प्रदान करता है, इसलिए जबकि फ़ील्ड के लिए सेट कुछ समझ में आता है, ऐसा लगता है कि यह सही नहीं हो सकता है।
जोशुआ टेलर

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

142
(set ls '(1 2 3 4)) => Error - ls has no value

(set 'ls '(1 2 3 4)) => OK

(setq ls '(1 2 3 4)) => OK - make ls to (quote ls) and then have the usual set

(setf ls '(1 2 3 4)) => OK - same as setq so far BUT

(setf (car ls) 10) => Makes ls '(10 2 3 4) - not duplicated by setq/set

12
मुझे लगता है कि आपका उत्तर शीर्ष मतदान वाले से अधिक स्पष्ट है। बहुत बहुत धन्यवाद।
CDR

2
@ सौर, कृपया उदाहरण कोड में "l" (ell) अक्षर को एक चर या प्रतीक के रूप में उपयोग करें। अंकीय 1. से
स्पष्ट

नहीं, मुझे अभी भी समझ में नहीं आया है कि कैसे (कार एलएस) एल-मूल्य हो सकता है या नहीं। क्या आप समझते हैं कि C में CLisp का अनुवाद कैसे किया जाता है? और एक क्लिस्प दुभाषिया कैसे लिखें?
पुनर्मिलन

@ user1952009 क्लिस्प एक आम लिस्प कार्यान्वयन है। यदि आप भाषा को स्वयं संदर्भित करना चाहते हैं, तो सबसे अधिक उपयोग किया जाने वाला संक्षिप्त नाम सीएल।
ssice

2
@ user1952009 के बाद (setq ls '(((1)))), (setf (car (car (car ls))) 5)अपरिभाषित व्यवहार है, क्योंकि मूल्य lsस्थिर है (जैसे सी में एक स्ट्रिंग शाब्दिक संशोधन)। के बाद (setq ls (list (list (list 1)))), सी। की (setf (car (car (car ls))) 5)तरह काम करता हैls->val->val->val = 5
काइल

21

setqसिर्फ setएक उद्धृत पहले arg के साथ की तरह है - (set 'foo '(bar baz))जैसा है (setq foo '(bar baz))setfदूसरी ओर, वास्तव में सूक्ष्म है - यह एक "अप्रत्यक्ष" जैसा है। मेरा सुझाव है http://www.nano.com/lisp/cmucl-tutorials/LISP-tutorial-16.html एक बेहतर तरीका के रूप में किसी भी सवाल का जवाब की तुलना में यह समझने आरंभ करने के लिए यहाँ दे सकते हैं ... संक्षेप में, हालांकि, setfले जाता है एक "संदर्भ" के रूप में पहला तर्क, ताकि उदाहरण के (aref myarray 3)लिए setfएक सरणी के अंदर एक आइटम सेट करने के लिए काम करेगा (पहले arg के रूप में )।


1
सेटक नाम के लिए सबसे अधिक समझ में आता है। याद करने के लिए आसान। धन्यवाद।
CDR

17

आप इसके setfस्थान पर उपयोग कर सकते हैं setया setqइसके विपरीत नहीं, क्योंकि setfचर के अलग-अलग तत्वों का मान भी सेट कर सकते हैं यदि चर में अलग-अलग तत्व हैं। नीचे दिए गए निर्वासन देखें:

सभी चार उदाहरण foo नाम के वेरिएबल को सूची (1, 2, 3) सौंपेंगे।

(set (quote foo) (list 1 2 3))    ;foo => (1 2 3)
(1 2 3)

(set 'foo '(1 2 3))   ;foo => (1 2 3) same function, simpler expression
(1 2 3)

(setq foo '(1 2 3))   ;foo => (1 2 3) similar function, different syntax
(1 2 3)

(setf foo '(1 2 3))   ;foo => (1 2 3) more capable function
(1 2 3)

setffooएक नए मूल्य के लिए सूची के एक सदस्य को स्थापित करने की अतिरिक्त क्षमता है ।

foo                   ;foo => (1 2 3) as defined above
(1 2 3)

(car foo)             ;the first item in foo is 1
1

(setf (car foo) 4)    ;set or setq will fail since (car foo) is not a symbol
4

foo                   ;the fist item in foo was set to 4 by setf
(4 2 3)

हालाँकि, आप एक प्रतीक मैक्रो को परिभाषित कर सकते हैं जो किसी एकल आइटम को पुन: प्रस्तुत करता है foo

(define-symbol-macro foo-car (car foo))    ; assumes FOO => (1 2 3)
FOO-CAR

foo-car               ;foo-car is now a symbol for the 1st item in foo
1

(setq foo-car 4)      ;set or setq can set the symbol foo-car 
4

foo                   ;Lisp macros are so cool
(4 2 3)

आप उपयोग कर सकते हैं defvarयदि आपने पहले से चर को परिभाषित नहीं किया है और अपने कोड में बाद तक इसे एक मूल्य नहीं देना चाहते हैं।

(defvar foo2)
(define-symbol-macro foo-car (car foo2))

13

एक के बारे में सोच सकते हैं SETऔर SETQनिम्न स्तर के निर्माणों जा रहा है।

  • SET प्रतीकों का मूल्य निर्धारित कर सकते हैं।

  • SETQ चर का मान सेट कर सकते हैं।

फिर SETFएक मैक्रो है, जो चीजों को स्थापित करने के कई प्रकार प्रदान करता है: प्रतीक, चर, सरणी तत्व, उदाहरण स्लॉट, ...

प्रतीकों और चरों के लिए कोई सोच सकता है जैसे कि SETFविस्तार SETऔर SETQ

* (macroexpand '(setf (symbol-value 'a) 10))

(SET 'A 10)


* (macroexpand '(setf a 10))         

(SETQ A 10)

तो SETऔर SETQकुछ की कार्यक्षमता को लागू करने के लिए उपयोग किया जाता है SETF, जो कि अधिक सामान्य निर्माण है। कुछ अन्य उत्तर आपको थोड़ा और जटिल कहानी बताते हैं, जब हम प्रतीक मैक्रोज़ को ध्यान में रखते हैं।


4

मैं पिछले उत्तरों में जोड़ना चाहूंगा कि सेटफ़ मैक्रो है जो विशिष्ट फ़ंक्शन को कॉल करता है जो उसके पहले तर्क के रूप में पारित किया गया था। विभिन्न प्रकार के तर्कों के साथ सेटफ के मैक्रो विस्तार के परिणामों की तुलना करें:

(macroexpand '(setf a 1))

(macroexpand '(setf (car (list 3 2 1)) 1))

(macroexpand '(setf (aref #(3 2 1) 0) 1))

कुछ प्रकार के तर्कों के लिए "सेटफ फ़ंक्शन" कहा जाएगा:

(defstruct strct field)
(macroexpand '(setf (strct-field (make-strct)) 1))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.