वाक्य रचना (++ a)
(incf a)
के लिए एक बेकार उर्फ है लेकिन आप के बाद वेतन वृद्धि के शब्दों चाहते लगता है:। वर्ष मान प्राप्त। सामान्य लिस्प में, यह prog1
के साथ किया जाता है, जैसा कि: (prog1 i (incf i))
। सामान्य लिस्प अविश्वसनीय या संदिग्ध मूल्यांकन आदेश से ग्रस्त नहीं है। पिछली अभिव्यक्ति का अर्थ है कि i
का मूल्यांकन किया गया है, और मूल्य कहीं भी छीन लिया गया है, तो (incf i)
का मूल्यांकन किया गया है, और तो स्टैश किए गए मान को वापस कर दिया जाता है।
पूरी तरह से बुलेट प्रूफ बनाना pincf
(पोस्ट -incf
) पूरी तरह से तुच्छ नहीं है। (incf i)
में अच्छी संपत्ति है कि i
का मूल्यांकन केवल एक बार किया जाता है। हम (pincf i)
भी उस संपत्ति के लिए चाहते हैं। और इसलिए सरल मैक्रो कम पड़ता है:
(defmacro pincf (place &optional (increment 1))
`(prog1 ,place (incf ,place ,increment))
यह अधिकार हम लिस्प के "काम जगह विश्लेषक" सामग्री है कि अनुमति देने के प्राप्त करने के लिए कहा जाता है get-setf-expansion
का सहारा लेना है ऐसा करने के लिए हमारी पहुंच को ठीक से संकलित करने के लिए मैक्रो:
(defmacro pincf (place-expression &optional (increment 1) &environment env)
(multiple-value-bind (temp-syms val-forms
store-vars store-form access-form)
(get-setf-expansion place-expression env)
(when (cdr store-vars)
(error "pincf: sorry, cannot increment multiple-value place. extend me!"))
`(multiple-value-bind (,@temp-syms) (values ,@val-forms)
(let ((,(car store-vars) ,access-form))
(prog1 ,(car store-vars)
(incf ,(car store-vars) ,increment)
,store-form)))))
सीएलआईएसपी के साथ कुछ परीक्षण। (नोट: get-setf-expansion
से सामग्री पर निर्भर विस्तार कार्यान्वयन-विशिष्ट कोड शामिल हो सकता है इसका मतलब यह नहीं हमारी मैक्रो पोर्टेबल नहीं है।!)
8]> (macroexpand `(pincf simple))
(LET* ((#:VALUES-12672 (MULTIPLE-VALUE-LIST (VALUES))))
(LET ((#:NEW-12671 SIMPLE))
(PROG1 #:NEW-12671 (INCF #:NEW-12671 1) (SETQ SIMPLE #:NEW-12671)))) ;
T
[9]> (macroexpand `(pincf (fifth list)))
(LET*
((#:VALUES-12675 (MULTIPLE-VALUE-LIST (VALUES LIST)))
(#:G12673 (POP #:VALUES-12675)))
(LET ((#:G12674 (FIFTH #:G12673)))
(PROG1 #:G12674 (INCF #:G12674 1)
(SYSTEM::%RPLACA (CDDDDR #:G12673) #:G12674)))) ;
T
[10]> (macroexpand `(pincf (aref a 42)))
(LET*
((#:VALUES-12679 (MULTIPLE-VALUE-LIST (VALUES A 42)))
(#:G12676 (POP #:VALUES-12679)) (#:G12677 (POP #:VALUES-12679)))
(LET ((#:G12678 (AREF #:G12676 #:G12677)))
(PROG1 #:G12678 (INCF #:G12678 1)
(SYSTEM::STORE #:G12676 #:G12677 #:G12678)))) ;
T
अब यहाँ एक महत्वपूर्ण परीक्षण का मामला है। यहां, स्थान में एक साइड इफेक्ट है: (aref a (incf i))
। यह एक बार मूल्यांकन किया जाना चाहिए!
[11]> (macroexpand `(pincf (aref a (incf i))))
(LET*
((#:VALUES-12683 (MULTIPLE-VALUE-LIST (VALUES A (INCF I))))
(#:G12680 (POP #:VALUES-12683)) (#:G12681 (POP #:VALUES-12683)))
(LET ((#:G12682 (AREF #:G12680 #:G12681)))
(PROG1 #:G12682 (INCF #:G12682 1)
(SYSTEM::STORE #:G12680 #:G12681 #:G12682)))) ;
T
तो क्या पहले ऐसा होता है कि A
और (INCF I)
मूल्यांकन किया जाता है है, और अस्थायी चर #:G12680
और #:G12681
हो जाते हैं। सरणी का उपयोग किया जाता है और मान #:G12682
में कैप्चर किया जाता है। फिर हमारे पास PROG1
है जो कि उस मूल्य को वापस करने के लिए बनाए रखता है। मान बढ़ाया गया है, और सीएलआईएसपी के system::store
फ़ंक्शन के माध्यम से सरणी स्थान पर वापस संग्रहीत किया गया है। ध्यान दें कि यह स्टोर कॉल अस्थायी चर का उपयोग करता है, मूल अभिव्यक्ति A
और I
नहीं। (INCF I)
केवल एक बार प्रकट होता है।
डुप्लिकेट नहीं है, लेकिन संबंधित: [? INCF की तरह एक विनाशकारी मैक्रो या समारोह लेखन] (http://stackoverflow.com/q/19485964/1281433) –