किसी सूची के माध्यम से लूपिंग करके मैं कई डिफ्यूज़ कैसे बना सकता हूँ?


11

मैं अपने emacs config को अनुकूलित करने पर काम कर रहा हूं जहां मैं गतिशील रूप से उन सभी विषयों के लिए इंटरैक्टिव फ़ंक्शन बना सकता हूं जो मेरे पास एक सूची में हैं।

नीचे निर्माण का एक सरलीकृत संस्करण है जो मैं काम करने की कोशिश कर रहा हूं।

;; List containing names of functions that I want to create
(setq my/defun-list '(zz-abc
                      zz-def
                      zz-ghi))

;; Elisp macro to create an interactive defun whose name
;; is passed as the macro argument
(defmacro my/create-defun (defun-name)
  `(defun ,defun-name ()
     (interactive)
     (let ((fn-name (symbol-name ',defun-name)))
       (message "Testing creation of function %s" fn-name))))

;; Loop to call the above macro for each element in the list
;; DOES *NOT* WORK
(dolist (name my/defun-list)
  (my/create-defun name))

लेकिन अगर मैं मैन्युअल रूप से लूप को अनियंत्रित करता हूं, तो यह काम करता है:

;; WORKS
(my/create-defun zz-abc)
(my/create-defun zz-def)
(my/create-defun zz-ghi)

लेकिन नीचे काम नहीं करता है, जहां मैं प्रतीक नामों में पास करता हूं (जो कि संभवतया तब होता है जब लूप अपने आप से अनियंत्रित हो जाता है)। मैक्रो तर्कों से पहले उद्धरणों पर ध्यान दें।

;; DOES *NOT* WORK
(my/create-defun 'zz-abc)
(my/create-defun 'zz-def)
(my/create-defun 'zz-ghi)

अपडेट करें

@Wvxvw की मदद के लिए धन्यवाद , आखिरकार मुझे यह काम मिल गया !

जैसा कि @wvxvw सुझाव देता है, मैं किसी भी और हर उपयोग के मामले के लिए बैच-जेनरिंग डिफ्यूज़ नहीं बनूंगा। यह एक विशेष उपयोग का मामला था XYZ, जहां नाम के एक विषय के लिए , मैं एक डिफ्यूजन उत्पन्न करना चाहता हूं जिसे नाम दिया load-theme/XYZगया है

  • अन्य सभी विषयों को सक्रिय करना जो सक्रिय हो सकते हैं
  • के लिए बुला load-themeरहा हैXYZ
  • उस विषय से संबंधित कुछ और कस्टम चीजें करना; मैं my/themesएलिस्ट के माध्यम से प्रत्येक थीम के लिए कस्टम सेटिंग्स में पास करता हूं ।

1
सब defunsअंदर डाल दो prognprognको शीर्ष-स्तरीय रूप होने की अनुमति दी जाती है (इस अर्थ में कि शीर्ष-स्तरीय रूपों पर लागू होने वाली हर चीज prognभी सामग्री पर लागू होती है)। लेकिन मैं इस तरह से कार्यों के निर्माण के औचित्य पर सवाल उठाऊंगा: क्यों नहीं, कहते हैं, मान के रूप में लंबोदर के साथ एक मेज है?
wvxvw

@wvxvw मुझे सुझाव समझ में नहीं आया। मेरे पास मैक्रो बनाने का सिर्फ एक डिफ्यूजन है जिसे मैं एक लूप में कई बार कॉल करना चाहता हूं। मैन्युअल रूप से अनियंत्रित उदाहरण यह दिखाने के लिए हैं कि मैंने इस मुद्दे का पता लगाने की कोशिश करते समय क्या काम किया और क्या नहीं किया। मेरा उद्देश्य एक सूची के बजाय एक एलिस्ट है और विभिन्न विषयों के लिए इंटरैक्टिव फ़ंक्शन बनाना है । वर्तमान में एलिस्ट में केवल conses शामिल हैं, लेकिन मैं प्रत्येक विषय के लिए कस्टम गुणों वाली सूचियों में परिवर्तित करने की योजना बना रहा हूं।
कौशल मोदी

ठीक है, आपने (my/create-defun name)3 बार कॉल किया है, इसलिए आपको name3 बार नामक फ़ंक्शन को परिभाषित करना चाहिए ।
उमर १

जवाबों:


13

यहाँ समझाने और कुछ सुझाव देने का प्रयास किया गया है।

(defmacro my/create-defun (defun-name)
  `(defun ,defun-name ()
     (interactive)
     (let ((fn-name (symbol-name ',defun-name)))
       (message "Testing creation of function %s" fn-name))))

(dolist (name my/defun-list)
  ;; Macros are meant to create code, not execute it.  Think
  ;; about simply substituting the contents of your macro here
  ;; what would you expect it to do?
  (my/create-defun name))

(dolist (name my/defun-list)
  ;; This is not something a compiler (or interpreter)
  ;; can work with, it needs all sources of the code it
  ;; is going to execute
  (defun defun-name ()
    (interactive)
    (let ((fn-name (symbol-name 'defun-name)))
      (message "Testing creation of function %s" fn-name))))

;; This works because you, indeed created three defuns
(my/create-defun zz-abc)
(my/create-defun zz-def)
(my/create-defun zz-ghi)

;; This doesn't work because `defun' macro expect the name of
;; the function to be a symbol (but you are giving it a list
;; `(quote zz-abc)'.
(my/create-defun 'zz-abc)
(my/create-defun 'zz-def)
(my/create-defun 'zz-ghi)

अब, इसे ठीक करने का प्रयास करते हैं:

;; Rewriting the original macro as a function and using a
;; macro to collect the generated forms gives:
(defun my/create-defun (defun-name)
  `(defun ,defun-name ()
     (interactive)
     (let ((fn-name (symbol-name ',defun-name)))
       (message "Testing creation of function %s" fn-name))))

(defmacro my/create-defuns (defuns)
  `(progn ,@(mapcar 'my/create-defun defuns)))

(macroexpand '(my/create-defuns (zz-abc zz-def zz-ghi)))
;; Just to make sure
(progn
  (defun zz-abc nil
    (interactive)
    (let ((fn-name (symbol-name (quote zz-abc))))
      (message "Testing creation of function %s" fn-name)))
  (defun zz-def nil
    (interactive)
    (let ((fn-name (symbol-name (quote zz-def))))
      (message "Testing creation of function %s" fn-name)))
  (defun zz-ghi nil
    (interactive)
    (let ((fn-name (symbol-name (quote zz-ghi))))
      (message "Testing creation of function %s" fn-name))))

एक चर से फ़ंक्शन नाम पढ़ने के साथ उदाहरण

(defvar my/functions '((func-1 . 1) (func-2 . 2) (func-3 . 3)))

(defun my/create-defun-n (defun-name n)
  `(defun ,defun-name ()
     (message "function: %s, n %d" ',defun-name ,n)))

(defmacro my/create-defuns-var ()
  `(progn ,@(mapcar
             (lambda (x) (my/create-defun-n (car x) (cdr x)))
             my/functions)))

(macroexpand '(my/create-defuns-var))
(progn
  (defun func-1 nil (message "function: %s, n %d" (quote func-1) 1))
  (defun func-2 nil (message "function: %s, n %d" (quote func-2) 2))
  (defun func-3 nil (message "function: %s, n %d" (quote func-3) 3)))

समस्या एक वैचारिक प्रकार की थी: मैक्रोज़ कोड बनाने के लिए हैं जब पर्यावरण इसे पढ़ना चाहता है। जब आप स्वयं कोड निष्पादित करते हैं (अपने प्रोग्राम के उपयोगकर्ता होने के नाते) तो यह करने के लिए पहले से ही बहुत देर हो चुकी है (पर्यावरण को तब तक पता होना चाहिए कि प्रोग्राम क्या है)।


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


4
मुझे लगता है कि अंतिम सीमांत नोट सभी बोल्ड कैप में होना चाहिए :)
abo-abo

धन्यवाद! उदाहरण के साथ यह बहुत अच्छी जानकारी है। जैसे ही मैं mapcarमुट्ठियों से प्रयोग कर रहा हूँ, मैं इसे एक उत्तर के रूप में स्वीकार करूँगा । यह मेरे वास्तविक उपयोग के मामले में काम नहीं करता है। मैं जितनी जल्दी हो सके इस में खुदाई करूँगा।
कौशल मोदी मोदी

@kaushalmodi आप देख सकते (mapcar (lambda (x) (message "argument: %s" x)) some-alist)हैं कि आपको क्या तर्क मिलता है, और वहां से काम करें। यदि यह एक साहचर्य सूची है, तो मुझे लगता है कि आउटपुट कुछ ऐसा होगा argument: (foo . bar), तो आप fooउपयोग कर सकते हैं carऔर कार्यों barका उपयोग कर सकते हैं cdr
wvxvw

हाँ, मैं भी ऐसा ही किया (सिर्फ इतना है कि मैं प्रयोग किया जाता है nthके बजाय fn carऔर cadr), लेकिन sequencepमें जाँच mapcarबाहर errored। मैं इनपुट के रूप में एक एलिस्ट प्रदान कर रहा था लेकिन फिर भी मैपकार को नहीं लगता था कि यह एक अनुक्रम था। अगर मैंने किया (sequencep my-alist), तो वह गैर-शून्य था। इसलिए मैं उलझन में हूँ .. मुझे अभी तक उस पर बहस करनी है।
कौशल मोदी

@kaushalmodi मैं दो कारणों से कल्पना कर सकते हैं: my-alistथा nilया आप भूल गए हैं (या अतिरिक्त जोड़ा) उद्धरण ताकि my-alistया तो एक प्रतीक था, या कुछ और होना करने के लिए आगे भी मूल्यांकित किया गया था। आप शायद अपने प्रश्न का विस्तार नए कोड के साथ करना चाहते हैं ताकि इसका उत्तर देना आसान हो जाए।
wvxvw

2
(dolist (fun '(foo bar baz))
  (defalias fun (lambda (a)
                  "I'm a function defined in `dolist'!"
                  (interactive)
                  (message a))))
(bar "See? No macro!")

बिल्कुल नहीं, लेकिन क्यों नहीं? : पी


0

मेरे पास इनिट में निम्नलिखित हैं:

(my/work-properties '("hostname" "username" "location"))

(defmacro jlp/make-def (name props doc &rest body)
  "Shortcut to programatically create new functions"
  (let ((funsymbol (intern name)))
    `(defun ,funsymbol ,props ,doc ,@body)))

(defun my/make-work-props (properties)
  "Create functions to retrieve properties from Org headlines."
  (dolist (prop properties)
    (let ((funsym   (format "my/org-get-%s" prop))
          (property (intern (format ":%s" (upcase prop))))
          (doc      (format "Retrieves `%s' from current headline"
                            (upcase prop)))
          (err (format "%s is not set" (capitalize prop))))
      (eval
       `(jlp/make-def ,funsym
                      ()
                      ,doc
                      (interactive)
                      (let ((x (or
                                (save-excursion
                                  (org-back-to-heading)
                                  (org-element-property
                                   ,property
                                   (org-element-at-point)))
                                (user-error ,err))))
                        (message "%s" x)
                         (kill-new x)))))))

(my/make-work-props my/org-work-properties)

यह शायद जरूरत से थोड़ा अधिक जटिल है (विशेष रूप से अतिरिक्त निष्कासन) लेकिन यह मुझे उन गुणों के लिए आवश्यक मानदंड उत्पन्न करने की अनुमति देता है (और स्ट्रिंग्स में सही जानकारी के साथ docstrings शामिल करें)।

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