मुझे पता है कि आप प्रोग्रामिंग समय पर परिवर्तनीय तर्कों के लिए एक प्रकार घोषित कर सकते हैं:

(defun foo (a b) (declare (type integer a b))

हालाँकि; मैं गतिशील रूप से प्रकार निर्दिष्ट करने में सक्षम होना चाहता हूं। मेरे पास एक मैक्रो है जो मुझे एक तर्क-सूची पास करके एक सूचियां (विपक्ष कोशिकाओं की सूची) बनाने देता है ... उदाहरण के लिए:

(defalist foo (x y z))  
--> returns function whose body ~ (list (cons 'x x) (cons 'y y) (cons 'z z))

मैं गतिशील रूप से तर्कों के प्रकारों को निर्दिष्ट करने में सक्षम होना चाहता हूं, जिस तरह से आप defun के भीतर होंगे, लेकिन मैक्रो के साथ प्रोग्रामेटिक रूप से जेनरेट किया जाएगा। मैंने घोषणा/अस्वीकृति का उपयोग करने का प्रयास किया है लेकिन मैं मुद्दों में भाग रहा हूं - ऐसा लगता है कि एसबीसीएल को संकलन समय पर निर्दिष्ट वास्तविक प्रकार की आवश्यकता है ... मैं एक defmacro के भीतर, कुछ ऐसा करने में सक्षम होना चाहता हूं:

 (mapcan #'(lambda (arg typ) (declare (type typ arg))) args-list types-list)

क्या सबसे अच्छा तरीका होगा यह करने का?

आपकी सहायताके लिए धन्यवाद!

1
Flywheel 7 पद 2020, 03:26

1 उत्तर

सबसे बढ़िया उत्तर

मुझे यकीन नहीं है कि यहां 'गतिशील' से आपका क्या मतलब है।

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

हालांकि, यदि आप वास्तव में मैक्रो की परिभाषा में प्रकार घोषित करने में सक्षम होना चाहते हैं, तो मैक्रोएक्सपेंशन संकलन समय पर (या ठीक पहले) होता है, इसलिए ये प्रकार वास्तव में स्थिर प्रकार की घोषणाएं हैं: defalist कुछ defun फॉर्म में जानकारी का विस्तार करने जा रहा है और आप बस उस फॉर्म में एक उपयुक्त declare जोड़ सकते हैं।

यहां ऐसा मैक्रो है (ध्यान दें, मुझे नहीं पता कि आपका defalist क्या करना है: यह वही है जो मैंने आविष्कार किया था), जो आपको प्रकार निर्दिष्ट करने की अनुमति देता है:

(defmacro defalist (name (&rest args/types) &body junk &key
                         (default-type t)
                         (checked-instead
                          ;; use explicit type checks if we're not
                          ;; using a Python-derived compiler.
                          #-(or SBCL CMUCL) t
                          #+(or SBCL CMUCL) nil))
  ;; Each argument should either be a name or (name type).
  (declare (ignore junk))               ;just to get indentation
  (assert (every (lambda (a/t)
                   (or (symbolp a/t)
                       (and (consp a/t)
                            (symbolp (first a/t))
                            (= (list-length a/t) 2))))
                 args/types)
      (args/types)
    "bad arguments ~A" args/types)
  (multiple-value-bind (args types)
      (loop for a/t in args/types
            collect (typecase a/t
                      (symbol a/t)
                      (cons (first a/t)))
            into the-args
            collect (typecase a/t
                      (symbol default-type)
                      (cons (second a/t)))
            into the-types
            finally (return (values the-args the-types)))
    `(defun ,name (,@args)
       ,(if checked-instead
            `(progn
               ,@(loop for a in args and tp in types
                       collect `(check-type ,a ,tp)))
          `(declare ,@(loop for a in args and tp in types
                            collect `(type ,tp ,a))))
       (list ,@(loop for a in args
                   collect `(cons ',a ,a))))))

और अब

(defalist foo (a b c))

तक फैलता है

(defun foo (a b c)
  (declare (type t a) (type t b) (type t c))
  (list (cons 'a a) (cons 'b b) (cons 'c c)))
(defalist foo (a b c)
  :default-type integer)

तक फैलता है

(defun foo (a b c)
  (declare (type integer a) (type integer b) (type integer c))
  (list (cons 'a a) (cons 'b b) (cons 'c c)))

और अंत में

(defalist foo ((a fixnum) (b float) c)
  :default-type integer)

तक फैलता है

(defun foo (a b c)
  (declare (type fixnum a) (type float b) (type integer c))
  (list (cons 'a a) (cons 'b b) (cons 'c c)))

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

यदि आप CMUCL कंपाइलर पर व्युत्पन्न कंपाइलर का उपयोग नहीं कर रहे हैं, तो इस तरह की घोषणाओं से कोड कम सुरक्षित हो सकता है। इसलिए मैक्रो इसका पता लगाने की कोशिश करता है, और उन कंपाइलरों में यह स्पष्ट चेक द्वारा प्रकार की घोषणाओं को बदल देता है। इसे checked-instead कीवर्ड से मैन्युअल रूप से नियंत्रित किया जा सकता है।

2
tfb 7 पद 2020, 21:40