पारदर्शी "पास-थ्रू" फंक्शन रैपर कैसे लिखें?


10

"पारदर्शी 'पास-थ्रू' फ़ंक्शन रैपर" से मेरा क्या अभिप्राय है, इसे कहते हैं wrapper, जो इसके सभी तर्क को किसी अन्य फ़ंक्शन में पास करने से परिणाम देता है, चलो इसे कॉल करें wrappee

यह Emacs Lisp में कैसे किया जाता है?

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

मैंने अपने प्रश्न का आंशिक उत्तर पोस्ट किया :

(defun wrapper (&rest args) (apply 'wrappee args))

यह केवल काम करता है जब wrappeeहै नहीं इंटरैक्टिव। जाहिरा तौर पर, जिस तरह से इंटरेक्टिव फ़ंक्शन उनके तर्क प्राप्त करते हैं वह एक अलग "चैनल" का प्रतिनिधित्व करता है जो कि (&rest args)भस्म से ढंका होता है । मुझे अभी भी wrappeeजिस चीज की आवश्यकता है, वह (&rest args)उस मामले के लिए हस्ताक्षर का समान रूप से-समरूप प्रतिपक्ष है जहां wrappeeएक संवादात्मक कार्य है।

(यह सवाल इस पहले के प्रश्न में वर्णित एक समस्या से प्रेरित था ।)


आगे जो मैं पूछ रहा हूँ, उसके स्पष्टीकरण की आवश्यकता है, नीचे कुछ उदाहरण दिए गए हैं, जो मैं के बाद पायथन और जावास्क्रिप्ट समकक्ष दिखा रहा हूँ।

पायथन में इस तरह के आवरण को लागू करने के लिए कुछ मानक तरीके नीचे दिखाए गए हैं:

def wrapper(*args, **kwargs):
    return wrappee(*args, **kwargs)

# or

wrapper = lambda *args, **kwargs: wrappee(*args, **kwargs)

(यहां *args"सभी स्थिति तर्क" **kwargsके लिए खड़ा है , और "सभी कीवर्ड तर्क" के लिए खड़ा है।)

जावास्क्रिप्ट समकक्ष कुछ इस तरह होगा:

function wrapper () { return wrappee.apply(this, arguments); }

// or

wrapper = function () { return wrappee.apply(this, arguments); }

रिकॉर्ड के लिए, मैं असहमत हूं कि यह प्रश्न कई तर्कों के साथ फ़ंक्शन में मैपकार को कैसे लागू किया जाए, इसका एक डुप्लिकेट है । मुझे यह समझाने में नुकसान हो रहा है कि, चूंकि दो प्रश्न मेरे लिए इतने स्पष्ट रूप से भिन्न हैं। यह पूछा जा रहा है कि "समझाएं कि एक सेब को नारंगी के बराबर क्यों नहीं माना जाना चाहिए"। मात्र प्रश्न इतना पागल है, कि एक संदेह कभी भी एक जवाब के साथ आ सकता है जो इसे पूछने वाले व्यक्ति को संतुष्ट करेगा।


क्या आपने सलाह / उदासीनता का उपयोग करने पर विचार किया?
वामासा

@wasamasa: नहीं, और, इसके अलावा, मैं यह देखने में विफल हूं कि इस प्रश्न पर सलाह / nadvice कैसे लागू होगी। किसी भी मामले में, मुझे adviceसामान समस्याग्रस्त लगता है जो मैं इसके बारे में स्पष्ट नहीं रहूंगा। वास्तव में, इस सवाल के लिए प्रेरणा एक अन्यथा
असंगत

1
@wasamasa: सलाह एक ही समस्या प्रस्तुत करती है। आप यह बता सकते हैं कि किसी भी आर्ग के साथ क्या करना है, लेकिन इसे इंटरैक्टिव बनाने के लिए आपको यह निर्दिष्ट करने की आवश्यकता है कि तर्क कैसे प्रदान किए जाने हैं। IOW, आपको एक interactiveयुक्ति प्रदान करने की आवश्यकता है ।
ड्रू

1
मेरे कहने का मतलब यह है कि आप जो भी करना चाहते हैं, उसके पहले और बाद में मूल इंटरैक्टिव फंक्शन की सलाह दे रहे हैं, इस तरह से आपको इंटरेक्टिव स्पेक के बारे में चिंता करने की आवश्यकता नहीं है।
वामासा

2
@wasamasa: हाँ, लेकिन यह अलग है। सलाह हमेशा किसी विशेष कार्य के लिए होती है, चाहे इंटरएक्टिव हो या न हो। और अगर यह एक कमांड है तो कोई समस्या नहीं है - इसका इंटरेक्टिव व्यवहार सलाह कमांड के लिए विरासत में मिला है (जब तक कि सलाह इंटरएक्टिव को पुनर्परिभाषित नहीं करता है)। यह सवाल एक मनमाना कार्य / आदेश के बारे में है, विशेष रूप से नहीं।
ड्रू

जवाबों:


11

बेशक यह interactiveविनिर्देशन को शामिल करना संभव है । हम यहाँ पर ललित के साथ काम कर रहे हैं ! (लिस्प वह भाषा है जहां सबसे महत्वपूर्ण निर्माण सूचियां हैं। कॉल करने योग्य रूप सिर्फ सूचियां हैं। इसलिए आप अपने निर्माण के बाद उनका निर्माण कर सकते हैं।)

आवेदन: आप स्वचालित रूप से कुछ कार्यों के लिए कुछ कार्यक्षमता जोड़ना चाहते हैं। विस्तारित कार्यों को नए नाम दिए जाने चाहिए ताकि defadviceयह लागू न हो।

पहला संस्करण जो आपके उद्देश्य के बिल्कुल अनुकूल है। हम सभी आवश्यक जानकारी के साथ fsetप्रतीक के फ़ंक्शन सेल ( ) को सेट करते हैं और हमारे अतिरिक्त सामान को जोड़ते हैं।wrapperwrappee

यह दोनों wrappeeपरिभाषाओं के लिए काम करता है । का पहला संस्करण wrappeeइंटरैक्टिव है दूसरा नहीं है।

(defun wrappee (num str)
  "Nontrivial wrappee."
  (interactive "nNumber:\nsString:")
  (message "The number is %d.\nThe string is \"%s\"." num str))

(defun wrappee (num str)
  "Noninteractive wrappee."
  (message "The number is %d.\nThe string is \"%s\"." num str))

(fset 'wrapper (list 'lambda
             '(&rest args)
             (concat (documentation 'wrappee t) "\n Wrapper does something more.")
             (interactive-form 'wrappee)
             '(prog1 (apply 'wrappee args)
            (message "Wrapper does something more."))))

लेकिन मैक्रो को परिभाषित करना अधिक सुविधाजनक है जो विस्तारित कार्यों का निर्माण करता है। इसके अलावा हम बाद में भी फ़ंक्शन नाम निर्दिष्ट कर सकते हैं। (स्वचालित संस्करण के लिए अच्छा है।)

नीचे दिए गए कोड को निष्पादित करने के बाद आप wrapper-interactiveइंटरएक्टिवली और wrapper-non-interactiveनॉन-इंटरैक्टिवली कॉल कर सकते हैं ।

(defmacro make-wrapper (wrappee wrapper)
  "Create a WRAPPER (a symbol) for WRAPPEE (also a symbol)."
  (let ((arglist (make-symbol "arglist")))
  `(defun ,wrapper (&rest ,arglist)
     ,(concat (documentation wrappee) "\n But I do something more.")
     ,(interactive-form wrappee)
     (prog1 (apply (quote ,wrappee) ,arglist)
       (message "Wrapper %S does something more." (quote ,wrapper))))))

(defun wrappee-interactive (num str)
  "That is the doc string of wrappee-interactive."
  (interactive "nNumber:\nsString:")
  (message "The number is %d.\nThe string is \"%s\"." num str))

(defun wrappee-non-interactive (format &rest arglist)
  "That is the doc string of wrappee-non-interactive."
  (apply 'message format arglist))

(make-wrapper wrappee-interactive wrapper-interactive)
(make-wrapper wrappee-non-interactive wrapper-non-interactive)
;; test of the non-interactive part:
(wrapper-non-interactive "Number: %d, String: %s" 1 "test")

ध्यान दें, अब तक मुझे डिक्लेयर फॉर्म को स्थानांतरित करने का कोई तरीका नहीं मिला है लेकिन यह भी संभव होना चाहिए।


2
हम्म, किसी ने इस जवाब को वोट दिया। मैं वास्तव में स्कोर के बारे में परवाह नहीं करता हूं, लेकिन मुझे परवाह है कि उत्तर का मतदान करने का कारण क्या है। यदि आप नीचे वोट करते हैं, तो कृपया एक टिप्पणी भी छोड़ दें! इससे मुझे उत्तर को बेहतर बनाने का मौका मिलेगा।
तोबियों

मैं निश्चित रूप से नहीं जानता, लेकिन यह किसी को भी पैकेज का कोड पढ़ने के लिए बाध्य करता है, इसका उपयोग डब्ल्यूटीएफ करता है। ज्यादातर मामलों में अधिक समझदार विकल्प इससे निपटने के लिए है और रैपिंग कर रहे एक फ़ंक्शन को मैन्युअल रूप से लिखना है (यह लागू होने के साथ या इंटरैक्टिव कल्पना के कुछ हिस्सों को फिर से लिखना है।
वामासा

2
@wasamasa I आंशिक रूप से सहमत है। फिर भी, ऐसे मामले हैं जहां स्वचालित इंस्ट्रूमेंटेशन अनिवार्य है। एक उदाहरण है edebug। इसके अलावा, ऐसे फ़ंक्शंस हैं, जहां- interactiveफंक्शनिफिकेशन फ़ंक्शन बॉडी की तुलना में काफी बड़ा है। ऐसे मामलों में interactiveविनिर्देश का पुनर्लेखन काफी थकाऊ हो सकता है। प्रश्न और उत्तर आवश्यक सिद्धांतों को संबोधित करते हैं।
तोबियास

1
व्यक्तिगत रूप से, मुझे यह उत्तर काफी शिक्षाप्रद लगता है, न केवल प्रश्न के दायरे के संबंध में, बल्कि यह भी कि यह मैक्रोज़ का एक प्राकृतिक अनुप्रयोग है, और कैसे डीफॉन से मैक्रो तक एक कदम है। धन्यवाद!
gsl

11

मुझे इसी तरह की समस्या को हल करना था nadvice.el, इसलिए यहाँ एक समाधान है (जो nadvice.el से कुछ कोड का उपयोग करता है):

(defun wrapper (&rest args)
  (interactive (advice-eval-interactive-spec
                (cadr (interactive-form #'wrappee))))
  (apply #'wrappee args))

अब तक पोस्ट किए गए अन्य समाधानों की तुलना में, यह एक सही ढंग से काम करने का लाभ है अगर wrappeeएक अलग इंटरैक्टिव ऐनक के साथ पुनर्परिभाषित हो जाता है (अर्थात यह पुराने चश्मे का उपयोग नहीं करेगा)।

बेशक, यदि आप चाहते हैं कि आपका रैपर वास्तव में पारदर्शी हो, तो आप इसे और अधिक सरलता से कर सकते हैं:

(defalias 'wrapper #'wrappee)

यह एकमात्र उत्तर है जो एक आवरण को परिभाषित करने की अनुमति देता है जो पाता है कि यह रनटाइम पर क्या लपेटता है। उदाहरण के लिए, मैं एक शॉर्टकट जोड़ना चाहता हूं जो कुछ कमांड द्वारा परिभाषित एक क्रिया करता है जिसे रनटाइम पर देखा जाता है। का प्रयोग advice-eval-interactive-specके रूप में यहाँ का सुझाव दिया मैं इंटरैक्टिव कल्पना का निर्माण कर सकते है कि गतिशील आवरण के अनुरूप हैं।
इगोर बुकानोव

इसे बनाने के लिए संभव है called-interactively-pलौटने tमें wrappee? नहीं है funcall-interactively, लेकिन कोईapply-interactively
clemera

1
@ कंप्यूटर: बेशक, आप चाहें तो कर सकते (apply #'funcall-interactively #'wrappee args)हैं। लेकिन आपको यह केवल तभी करना चाहिए जब फ़ंक्शन को अंतःक्रियात्मक रूप से कहा जाता है, इसलिए कुछ ऐसा (apply (if (called-interactively-p 'any) #'funcall-interactively #'funcall) #'wrappee args)
स्टीफन

हा, धन्यवाद! किसी तरह मेरे बॉक्स के बाहर सोच नहीं सकता था।
क्लेमर

1

संपादित करें: टोबियास का उत्तर इस से बेहतर है, क्योंकि यह सटीक संवादात्मक रूप और लिपटे फ़ंक्शन के डॉकस्ट्रिंग को प्राप्त करता है।


हारून हैरिस और kjo के जवाब को मिलाकर, आप कुछ इस तरह का उपयोग कर सकते हैं:

(defmacro my-make-wrapper (fn &optional name)
  "Return a wrapper function for FN defined as symbol NAME."
  `(defalias ',(or (eval name)
                   (intern (concat "my-" (symbol-name (eval fn)) "-wrapper")))
     (lambda (&rest args)
       ,(format "Generic wrapper for %s."
                (if (symbolp (eval fn))
                    (concat "`" (symbol-name (eval fn)) "'")
                  fn))
       (interactive)
       (if (called-interactively-p 'any)
           (call-interactively ,fn)
         (apply ,fn args)))))

उपयोग:

(my-make-wrapper 'find-file 'wrapper-func)

दोनों के साथ कॉल रैपर:

(wrapper-func "~/.emacs.d/init.el")

M-x wrapper-func

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