2012-12-25 17 views
18

प्रश्न के बारे में कीवर्ड इस्तेमाल नहीं किया जाता है, लेकिन वास्तव में के बारे में कीवर्ड कार्यान्वयन। उदाहरण के लिए, जब मैं कीवर्ड पैरामीटर के साथ कुछ फ़ंक्शन बनाता हूं और कॉल करता हूं:कीवर्ड सामान्य लिस्प में कैसे काम करते हैं?

(defun fun (&key key-param) (print key-param)) => FUN 
(find-symbol "KEY-PARAM" 'keyword) => NIL, NIL ;;keyword is not still registered 
(fun :key-param 1) => 1 
(find-symbol "KEY-PARAM" 'keyword) => :KEY-PARAM, :EXTERNAL 

किसी तर्क को पारित करने के लिए किसी कीवर्ड का उपयोग कैसे किया जाता है? कीवर्ड वे प्रतीक हैं जिनके मूल्य स्वयं हैं, तो किसी कीवर्ड का उपयोग करके संबंधित पैरामीटर को कैसे बाध्य किया जा सकता है?

कीवर्ड के बारे में एक और सवाल - कीवर्ड का उपयोग पैकेज को परिभाषित करने के लिए किया जाता है।

(defpackage :KEY-PARAM) => #<The KEY-PARAMETER package, 0/16 ... 
(in-package :KEY-PARAM) => #<The KEY-PARAMETER package, 0/16 ... 
(defun fun (&key key-param) (print key-param)) => FUN 
(fun :KEY-PARAM 1) => 1 

कैसे प्रणाली पैकेज का नाम और समारोह पैरामीटर नाम के बीच :KEY-PARAM के उपयोग भेद करता है: हम एक पैकेज पहले से ही विद्यमान कीवर्ड के साथ नामित किया गया परिभाषित कर सकते हैं? इसके अलावा हम कुछ और अधिक जटिल बना सकते हैं, तो हम समारोह KEY-PARAM को परिभाषित करने और इसे निर्यात (वास्तव में ढंग से काम नहीं है, लेकिन नाम) यदि:

(in-package :KEY-PARAM) 
(defun KEY-PARAM (&key KEY-PARAM) KEY-PARAM) => KEY-PARAM 
(defpackage :KEY-PARAM (:export :KEY-PARAM)) 
    ;;exporting function KEY-PARAM, :KEY-PARAM keyword is used for it 
(in-package :CL-USER) => #<The COMMON-LISP-USER package, ... 
(KEY-PARAM:KEY-PARAM :KEY-PARAM 1) => 1 
    ;;calling a function KEY-PARAM from :KEY-PARAM package with :KEY-PARAM parameter... 

सवाल एक ही है, कैसे कॉमन लिस्प यहां कीवर्ड :KEY-PARAM के उपयोग भेद करता है ?

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

उत्तर

10

कीवर्ड पैरामीटर के पूर्ण विवरण के लिए Common Lisp Hyperspec देखें। ध्यान दें कि

(defun fun (&key key-param) ...) 

वास्तव में के लिए कम है:

(defun fun (&key ((:key-param key-param))) ...) 

कोई keyword पैरामीटर का पूरा वाक्य रचना है:

((keyword-name var) default-value supplied-p-var) 

default-value और supplied-p-var वैकल्पिक हैं। हालांकि keyword-name के रूप में एक कीवर्ड प्रतीक का उपयोग करना पारंपरिक है, इसकी आवश्यकता नहीं है; यदि आप (keyword-name var) के बजाय var निर्दिष्ट करते हैं, तो यह keyword-name को var के समान नाम वाले कीवर्ड पैकेज में प्रतीक होने के लिए डिफ़ॉल्ट बनाता है।

तो, उदाहरण के लिए, तुम कर सकते हो:

(defun fun2 (&key ((myoption var))) (print var)) 

और उसके बाद के रूप में यह कहते हैं:

(fun 'myoption 3) 

जिस तरह से यह आंतरिक रूप से काम करता है जब समारोह बुलाया जा रहा है, इसके माध्यम से कदम तर्क सूची, तर्कों के जोड़े एकत्रित <label, value>। प्रत्येक label के लिए, यह है कि keyword-name के साथ एक पैरामीटर के लिए पैरामीटर सूची में लग रहा है, और value करने के लिए इसी var बांधता है।

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

पैकेज परिभाषित करते समय कीवर्ड तर्कों का उपयोग और चर निर्यात करने के लिए फिर से एक सम्मेलन है। DEFPACKAGE, IN-PACKAGE, EXPORT, आदि केवल नाम वे दिया जाता है के बारे में परवाह है, न कि क्या पैकेज क्या है। आप

(defpackage key-param) 

लिख सकता है और यह आमतौर पर बस के रूप में अच्छी तरह से काम करेगा। कारण कई प्रोग्रामर ऐसा नहीं करते हैं क्योंकि यह अपने स्वयं के पैकेज में एक प्रतीक को प्रशिक्षित करता है, और यह कभी-कभी पैकेज विवाद पैदा कर सकता है यदि ऐसा होता है कि ऐसा प्रतीक होता है जो वे किसी अन्य पैकेज से आयात करने का प्रयास कर रहे हैं। कीवर्ड का उपयोग इन पैरामीटर को एप्लिकेशन के पैकेज से तलाक देता है, इस तरह की संभावित समस्याओं से परहेज करता है।

नीचे की रेखा है: जब आप एक प्रतीक का उपयोग कर रहे हैं और आप केवल इसके नाम की परवाह करते हैं, इसकी पहचान नहीं, अक्सर कीवर्ड का उपयोग करना सबसे सुरक्षित होता है।

अंत में, जब वे विभिन्न तरीकों से उपयोग किए जाते हैं तो कीवर्ड को अलग करने के बारे में। एक कीवर्ड सिर्फ एक प्रतीक है। यदि यह किसी ऐसे स्थान पर उपयोग किया जाता है जहां फ़ंक्शन या मैक्रो केवल सामान्य पैरामीटर की अपेक्षा करता है, तो उस पैरामीटर का मान प्रतीक होगा। यदि आप ऐसे फ़ंक्शन को कॉल कर रहे हैं जिसमें &key तर्क हैं, तो यही एकमात्र समय है जब वे मानकों के साथ तर्कों को जोड़ने के लिए लेबल के रूप में उपयोग किए जाते हैं।

+0

धन्यवाद! सबकुछ अब स्पष्ट है, यह वास्तव में सहायक है! – TheEnt

+1

@ बाड़ार * "** (मज़ेदार मज़ा (और कुंजी कुंजी-param) ...) ** वास्तव में निम्न के लिए छोटा है: ** (मज़ेदार मज़ा (और कुंजी ((: key-param key-param))) ...) ** "* अपवाद के साथ कि पहले के बाद," कुंजी-पैराम "नामक एक प्रतीक को अभी तक कीवर्ड पैकेज में इंटर्न नहीं किया गया है (कम से कम ओपी की प्रतिलेख के अनुसार)।अगर यह एक शॉर्टेंड था जहां आर्किगिस्ट का विस्तार किया जा रहा था (और शायद एक कार्यान्वयन ऐसा कर सकता था; मुझे यकीन नहीं है कि इसकी अनुमति होगी या नहीं), तो कीवर्ड मैक्रो-विस्तार समय पर प्रशिक्षित किया गया होगा। (यह विशेष रूप से महत्वपूर्ण नहीं है, लेकिन यह defun के कार्यान्वयन में से कुछ "रिसाव" (या नहीं) इंगित करता है।) –

1

कीवर्ड के विभिन्न उपयोगों को अलग करने के लिए "सिस्टम" की आवश्यकता नहीं है। वे सिर्फ नाम के रूप में उपयोग किया जाता है।

(defparameter *language-scores* '(:basic 0 :common-lisp 5 :python 3)) 
(defparameter *price* '(:basic 100 :fancy 500)) 

एक समारोह एक भाषा के स्कोर उपज:

(defun language-score (language &optional (language-scores *language-scores*)) 
    (getf language-scores language)) 

कीवर्ड, जब language-score के साथ प्रयोग किया, नामित विभिन्न प्रोग्रामिंग भाषाओं: उदाहरण के लिए, दो plists कल्पना

CL-USER> (language-score :common-lisp) 
5 

अब, *price* में *language-scores* में कीवर्ड को अलग करने के लिए सिस्टम क्या करता है? बिल्कुल कुछ नहीं। कीवर्ड अलग-अलग डेटा संरचनाओं में अलग-अलग चीजों को नामित करने वाले नाम हैं। वे प्राकृतिक भाषा में homophones की तुलना में अधिक विशिष्ट नहीं हैं - उनका उपयोग निर्धारित करता है कि किसी दिए गए संदर्भ में उनका क्या मतलब है।

उपरोक्त उदाहरण में, कुछ भी नहीं एक गलत संदर्भ के साथ समारोह का उपयोग करने से हमें रोकता है:

(language-score :basic *prices*) 
100 

भाषा नहीं-तो-कल्पना प्रोग्रामिंग के लिए हमें ऐसा करने से रोकने के लिए कुछ और कीवर्ड के लिए किया था भाषा और नॉन-फैंसी उत्पाद वही हैं।

इसे रोकने के लिए कई संभावनाएं हैं: पहली जगह में language-score के लिए वैकल्पिक तर्क की इजाजत दी है, यह externing के बिना किसी अन्य पैकेज में *prices* डाल, एक शाब्दिक बंधन से अधिक बंद करने के बजाय विश्व स्तर पर विशेष *language-scores* का उपयोग करते समय केवल करने के लिए साधन उजागर प्रविष्टियां जोड़ें और पुनर्प्राप्त करें।शायद कोड आधार या सम्मेलन की हमारी समझ हमें ऐसा करने से रोकने के लिए पर्याप्त है। मुद्दा यह है कि: सिस्टम को अलग-अलग कीवर्ड को अलग करना आवश्यक नहीं है जिसे हम कार्यान्वित करना चाहते हैं।

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

+0

धन्यवाद! एक और सवाल, क्या यह जांचना संभव है कि क्या कार्यान्वयन कीवर्ड को तारों में परिवर्तित करता है या नहीं? तारों को कीवर्ड को कम करना संभव है? मेरा मतलब है कि जब लिस्प पाठक को एक खोजशब्द मिल जाता है तो यह एक विशेष प्रकार की स्ट्रिंग के रूप में इसे पार करता है। – TheEnt

+0

यह जांचने के लिए कि कार्यान्वयन आंतरिक रूप से कैसे काम करता है, आपको स्रोत कोड (या विस्तृत कार्यान्वयन-विशिष्ट दस्तावेज़ीकरण) पर एक नज़र रखना होगा। पैकेज नामों के मामले में, मैं तारों की तुलना करने के लिए कार्यान्वयन मानता हूं, क्योंकि अन्यथा (डिफ़ॉल्ट पाठक सेटिंग्स के साथ) केस-सूचना खो जाएगी। जबकि दो पैकेज "foo" और "foo" अलग हैं, दो कीवर्ड 'foo' और': Foo 'नहीं हैं। वे दोनों एक ही 'प्रतीक-नाम', "खाद्य" के साथ प्रशिक्षित हैं। (लेकिन फिर, इसे रोकने के लिए ': | Foo |' भी है।) – danlei

4

अच्छा मैनुअल Chapter 21 of PCL है।

संक्षेप में अपने प्रश्नों का उत्तर देना:

  • कीवर्ड, keyword पैकेज में प्रतीकों निर्यात किया जाता है जिससे आप न केवल :a के रूप में उन्हें का उल्लेख कर सकते हैं, लेकिन समारोह तर्क में भी keyword:a रूप

  • कीवर्ड सूचियां (lambda-list एस कहा जाता है) शायद, निम्न तरीके से कार्यान्वित किए गए हैं।

    (let ((key-param (getf args :key-param))) 
        body) 
    
  • जब आप एक कीवर्ड का उपयोग एक पैकेज नाम के लिए यह वास्तव में एक string-designator के रूप में प्रयोग किया जाता है: &key संशोधक की उपस्थिति में lambda प्रपत्र इस के समान कुछ में विस्तार किया गया है। यह एक लिस्प अवधारणा है जो तारों से निपटने वाले एक निश्चित कार्य को पारित करने की अनुमति देती है, जिसे बाद में प्रतीकों के रूप में उपयोग किया जा रहा है (विभिन्न नामों के लिए: पैकेज, कक्षाएं, कार्य, इत्यादि) न केवल स्ट्रिंग्स, बल्कि कीवर्ड और प्रतीकों ।

    (defpackage "KEY-PARAM" ...) 
    

    लेकिन आप साथ ही उपयोग कर सकते हैं: एक पाठक मैक्रो

    (defpackage :key-param ...) 
    

    और

    (defpackage #:key-param ...) 
    

    (यहाँ #: है तो, परिभाषित करने के लिए/उपयोग पैकेज बुनियादी तरीका वास्तव में यह है अनियंत्रित प्रतीकों को बनाने के लिए; और इस तरह से पसंदीदा एक है, क्योंकि आप प्रक्रिया में अनियंत्रित कीवर्ड नहीं बनाते हैं)।

    बाद वाले दो रूपों को ऊपरी-केस स्ट्रिंग में परिवर्तित कर दिया जाएगा। तो एक कीवर्ड एक कीवर्ड रहता है, और एक पैकेज को उस कीवर्ड से परिवर्तित स्ट्रिंग के रूप में नामित किया जाता है।

समेकित करने के लिए, कीवर्ड के पास स्वयं का मूल्य होता है, साथ ही साथ कोई अन्य प्रतीक भी होता है। अंतर यह है कि कीवर्ड को keyword पैकेज या इसके स्पष्ट उपयोग के साथ स्पष्ट योग्यता की आवश्यकता नहीं है। और अन्य प्रतीकों के रूप में वे वस्तुओं के नाम के रूप में काम कर सकते हैं। उदाहरण के लिए, उदाहरण के लिए, आप किसी कीवर्ड के साथ फ़ंक्शन का नाम दे सकते हैं और यह प्रत्येक पैकेज में "जादुई रूप से" पहुंच योग्य होगा :) विवरण के लिए @ Xach's blogpost देखें।

+0

धन्यवाद! '(getf: key-param args)' - वास्तव में अच्छी व्याख्या है। साथ ही, मैंने कीवर्ड-नामित फ़ंक्शंस का प्रयास किया, लिस्पार्क्स में कुछ '(defun: test() "hi") जैसे' त्रुटि का कारण बनता है 'फ़ंक्शन परिभाषित करना: पैकेज KEYWORD से दिखाई देने वाला परीक्षण। (लेकिन एक डीबगर विकल्प है "वैसे भी इसे परिभाषित करें "), जबकि एसबीसीएल में सबकुछ काम करता है। – TheEnt

+0

आपका स्वागत है! मुझे यह भी कहना है कि मैंने गलत तरीके से इसे गलत तरीके से लिखा है - उचित तरीका है '(getf args: key-param) ':) –

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