मैं एक बचाव के पुनर्मूल्यांकन को कैसे मजबूर कर सकता हूं?


21

मान लीजिए कि मेरे पास एक Emacs लिस्प बफर है जिसमें शामिल हैं:

(defvar foo 1)

अगर मैं फोन eval-last-sexpया eval-buffer, foo1. करने के लिए बाध्य किया जाता है तो मैं तो इस बफर को संपादित करें:

(defvar foo 2)

eval-last-sexpऔर eval-bufferइस लाइन को फिर से निष्पादित न करें, इसलिए fooअभी भी 1 है।

यह विशेष रूप से चुनौतीपूर्ण है जब ऐसे कई बयान हैं और मुझे नीचे ट्रैक करना है कि किन लाइनों का पुनर्मूल्यांकन नहीं किया जा रहा है।

मैंने सिर्फ Emacs को पुनरारंभ करने पर ध्यान दिया और फिर (require 'foo), लेकिन फिर मुझे किसी भी पुराने .elc फ़ाइलों को लोड करने से बचने के लिए सावधान रहना होगा।

मैं पूरी तरह से सकारात्मक कैसे हो सकता हूं कि वर्तमान फ़ाइल में परिभाषित चर और फ़ंक्शन एक ही स्थिति में हैं क्योंकि लोडिंग कोड नए इमैक उदाहरण में लोड हो रहा है?


आप " बिल्कुल, सकारात्मक रूप से सुनिश्चित नहीं हो सकते हैं कि Emacs एक ऐसी स्थिति में है जो कोड को एक नए Emacs उदाहरण में नए सिरे से लोड करने के समान है " बस ऐसा किए बिना। यदि आप यह सुनिश्चित करना चाहते हैं कि केवल यह और अन्य वैश्विक चर हैं , तो आप उनके मानों का उपयोग करके निकाल सकते हैं makunboundऔर फिर बफर में कोड का पुनर्मूल्यांकन कर सकते हैं ।
आकर्षित किया

ज़रूर, साइड इफेक्ट्स जैसे (मूर्खतापूर्ण कोड) (incf emacs-major-version)मैं बार-बार होने के साथ रह सकता हूं। मुझे बहुत सारे defvarरूपों के साथ कोड को हैक करने में दिलचस्पी है ।
विल्फ्रेड ह्यूजेस

जवाबों:


29

जैसा कि अन्य उत्तरों में बताया गया है, defvarफॉर्म का उपयोग करके मूल्यांकन करना eval-last-sexpडिफ़ॉल्ट मान को रीसेट नहीं करता है।

इसके बजाय, आप उपयोग कर सकते हैं eval-defun(करने के लिए बाध्य C-M-xमें emacs-lisp-modeहै, जो व्यवहार आप एक विशेष अपवाद के रूप में चाहते हैं लागू करता है डिफ़ॉल्ट रूप से):

यदि वर्तमान डिफ्यूजन वास्तव में एक कॉल है defvarया defcustom, इसका मूल्यांकन इस तरह से करता है, तो इसकी प्रारंभिक मूल्य अभिव्यक्ति का उपयोग करके चर को रीसेट करता है, भले ही चर में पहले से ही कुछ अन्य मूल्य हो। (सामान्य रूप से defvarऔर defcustomयदि पहले से ही एक है तो मूल्य में परिवर्तन न करें।)


यदि आपको एक बफर की पूरी सामग्री का मूल्यांकन करने की आवश्यकता है, तो आप एक फ़ंक्शन लिख सकते हैं जो शीर्ष-स्तर के रूपों को चालू करता है और eval-defunप्रत्येक पर कॉल करता है। कुछ इस तरह काम करना चाहिए:

(defun my/eval-buffer ()
  "Execute the current buffer as Lisp code.
Top-level forms are evaluated with `eval-defun' so that `defvar'
and `defcustom' forms reset their default values."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (while (not (eobp))
      (forward-sexp)
      (eval-defun nil))))

5
यह उत्तर है। नकली बचाव या अतिरिक्त सेट की कोई आवश्यकता नहीं है। के eval-defunबजाय का उपयोग करें eval-last-sexp । आप एक फ़ंक्शन भी लिख सकते हैं eval-defunजो बफर में प्रत्येक फॉर्म पर कॉल करता है , और इसके बजाय इसका उपयोग करता है eval-buffer
मालाबार

1
@Malabarba इस पोस्ट में सवाल का जवाब देने की कमी है। के eval-defunबजाय का उपयोग करें eval-last-sexp, सुनिश्चित करें, लेकिन कठिनाई के लिए है eval-buffer
गिल्स एसओ- बुराई को रोकें '

@ गिल्स हां, आप सही कह रहे हैं। मैंने eval-defunबफर में प्रत्येक शीर्ष-स्तरीय फॉर्म पर कॉल करने के @ मालाबार के विचार का एक अस्थायी कार्यान्वयन जोड़ा ।
ffevotte

1
यह दृष्टिकोण काम नहीं करता है अगर defvarअंदर नहीं है defun। उदाहरण: (progn (defvar foo "bar"))
कौशल मोदी

2
@kaushalmodi बाद के उदाहरण जिन्हें आप उद्धृत करते हैं (नियमित भावों को संग्रहित करने वाले चर) बहुत कुछ ऐसे लगते हैं जिनके लिए उम्मीदवार defconst(जो हमेशा पुनर्मूल्यांकन करते हैं)। अनंत कोष्ठक
आया

5

जैसे अन्य उत्तर कहते हैं, यह वैसे ही है जैसे डिफावर काम करता है, लेकिन आप इसके चारों ओर प्राप्त कर सकते हैं, यह सब के बाद भी स्पष्ट है।

आप अस्थायी रूप से यह परिभाषित कर सकते हैं कि अगर आप चाहें और उस समय के दौरान डिफावर कैसे काम करता है, तो उन पैकेजों को पुनः लोड करें जिन्हें आप रीसेट करना चाहते हैं।

मैंने एक मैक्रो लिखा है, जहां शरीर के मूल्यांकन के दौरान, डिफ़र्वर्स मानों का हमेशा पुनर्मूल्यांकन किया जाएगा।

(defmacro my-fake-defvar (name value &rest _)
  "defvar impersonator that forces reeval."
  `(progn (setq ,name ,value)
          ',name))

(defmacro with-forced-defvar-eval (&rest body)
  "While evaluating, any defvars encountered are reevaluated"
  (declare (indent defun))
  (let ((dv-sym (make-symbol "old-defvar")))
    `(let ((,dv-sym (symbol-function 'defvar)))
       (unwind-protect
           (progn
             (fset 'defvar (symbol-function 'my-fake-defvar))
             ,@body)
         (fset 'defvar ,dv-sym)))))

उदाहरण उपयोग:

file_a.el

(defvar my-var 10)

file_b.el

(with-forced-defvar-eval
  (load-file "file_a.el")
  (assert (= my-var 10))
  (setq my-var 11)
  (assert (= my-var 11)
  (load-file "file_a.el")
  (assert (= my-var 10))

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

आपके मामले में आप कर सकते हैं

(with-forced-defvar-eval (require 'some-package))

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

वैकल्पिक कार्यान्वयन

इसका उपयोग करके आप विश्व स्तर पर केवल डिफ्वेयर को फिर से परिभाषित कर सकते हैं और यह नियंत्रित कर सकते हैं कि यह प्रतीक के मूल्य को INIT-VALUE arg पर सेट करेगा या नहीं, भले ही प्रतीक को नए defvar-always-reeval-valuesप्रतीक के मान को बदलकर परिभाषित किया गया हो ।

;; save the original defvar definition
(fset 'original-defvar (symbol-function 'defvar))

(defvar defvar-always-reeval-values nil
  "When non-nil, defvar will reevaluate the init-val arg even if the symbol is defined.")

(defmacro my-new-defvar (name &optional init-value docstring)
  "Like defvar, but when `defvar-always-reeval-values' is non-nil, it will set the symbol's value to INIT-VALUE even if the symbol is defined."
  `(progn
     (when defvar-always-reeval-values (makunbound ',name))
     (original-defvar ,name ,init-value ,docstring)))

;; globally redefine defvar to the new form
(fset 'defvar (symbol-function 'my-new-defvar))

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

यदि आपको defvarएक मैक्रो के साथ फिर से परिभाषित करने की आवश्यकता है , तो आप संभवतः इसके बजाय मूल defvarरूप को प्रीफ़िक्स करने से बेहतर होंगे makunbound, बजाय इसे बदलने के setq
ffevotte

हां, यह एक भयानक विचार है, और इसका उपयोग केवल उन चीजों के लिए किया जाना चाहिए जैसे कि आपके स्क्रैच बफर में एक लोड किए गए पैकेज के दोषों को पुनर्मूल्यांकन करने के लिए, आपको कभी भी ऐसा कुछ जहाज नहीं करना चाहिए।
जॉर्डन बियोन्डो

@ फ्रांसेस्को भी आप मेकबाउंड संस्करण के बारे में सही हैं, मैंने इसे लागू किया था, लेकिन विचार से दूर भटक गया, मैंने एक विकल्प के रूप में अपने उत्तर पर उस कोड को डाल दिया है।
जॉर्डन बियोनडो

3

defvarमूल्यांकन किया जा रहा है और कर रही है आप वास्तव में क्या निर्दिष्ट किया है। हालाँकि, defvarकेवल एक प्रारंभिक मान सेट करता है:

वैकल्पिक तर्क INITVALUE का मूल्यांकन किया जाता है, और SYMBOL सेट करने के लिए उपयोग किया जाता है, केवल अगर SYMBOL का मूल्य शून्य है।

इसलिए आप जो चाहते हैं उसे प्राप्त करने के लिए आपको या तो पुनर्मूल्यांकन करने से पहले चर को खोलना होगा, जैसे

(makunbound 'foo)

या setqमान सेट करने के लिए उपयोग , उदा

(defvar foo nil "My foo variable.")
(setq foo 1)

यदि आपको यहां डॉकस्ट्रिंग निर्दिष्ट करने की आवश्यकता नहीं है, तो आप defvarपूरी तरह से छोड़ सकते हैं।

यदि आप वास्तव में उपयोग करना चाहते हैं defvarऔर स्वचालित रूप से इसे defvarखोलना चाहते हैं, तो आपको वर्तमान बफर (या क्षेत्र, या अंतिम सेक्सप, आदि) में कॉल खोजने के लिए एक फ़ंक्शन लिखने की आवश्यकता होगी ; makunboundहर एक को बुलाओ ; और फिर वास्तविक निष्कासन करें।


मैं एक eval-bufferरैपर के साथ खेलना बंद कर रहा था , जो पहले सब कुछ खोल देगा, लेकिन @ फ्रांसेस्को का जवाब eval-defunवास्तव में है कि आप क्या चाहते हैं।
ग्लूकोज १

1

निम्नलिखित मैक्रो eval-defunको इसके सहायक कार्यों को ट्रेस करके और इसे संशोधित करके बनाया गया था ताकि किसी विशेष बफर के क्षेत्र का मूल्यांकन करना आवश्यक न हो। मुझे संबंधित थ्रेड में मदद की आवश्यकता थी एक स्ट्रिंग के लिए एक अभिव्यक्ति परिवर्तित करना , और @Tobias बचाव में आया - मुझे सिखाना कि अपूर्ण फ़ंक्शन को मैक्रो में कैसे परिवर्तित किया जाए। मुझे नहीं लगता कि हमें eval-sexp-add-defvarsपहले की जरूरत है elisp--eval-defun-1, लेकिन अगर कोई सोचता है कि यह महत्वपूर्ण है, तो कृपया मुझे बताएं।

;;; EXAMPLE:
;;;   (defvar-reevaluate
;;;     (defvar undo-auto--this-command-amalgamating "hello-world"
;;;     "My new doc-string."))

(defmacro defvar-reevaluate (input)
"Force reevaluation of defvar."
  (let* ((string (prin1-to-string input))
        (form (read string))
        (form (elisp--eval-defun-1 (macroexpand form))))
    form))

0

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

यह ओवरकिल हो सकता है, लेकिन आप अपनी फ़ाइल को इस तरह से अपडेट कर सकते हैं यदि आप आसानी fooसे इसके नए डिफ़ॉल्ट मान को अपडेट करने में सक्षम होना चाहते हैं ।

(defvar foo 2)
(setq foo 2)

लेकिन इसके लिए आवश्यक है कि आप अपने कोड में दो स्थानों पर डिफ़ॉल्ट मान बनाए रखें। आप यह भी कर सकते हैं:

(makunbound 'foo)
(defvar foo 2)

लेकिन अगर ऐसा कोई मौका है जो fooकहीं और घोषित किया जाता है तो आपको इससे निपटने के लिए कुछ दुष्प्रभाव हो सकते हैं।


एक जटिल मोड में परिवर्तनों का परीक्षण करने की कोशिश करते समय यह मुश्किल है। मैं कोड को बदलना नहीं चाहूंगा। विशेष रूप से eval-defunव्यवहार करता है defvar, इसलिए निश्चित रूप से पूरे बफ़र्स के लिए कुछ समान है?
विल्फ्रेड ह्यूजेस

@WilfredHughes मुझे यकीन नहीं है कि आपका मतलब "पूरे बफ़र्स के लिए कुछ है।" आप एक एकल फ़ंक्शन चाहते हैं makunboundजो वर्तमान बफर में घोषित किए गए किसी भी चर को फिर से मूल्यांकन करेगा? आप अपना लिख ​​सकते हैं, लेकिन मुझे नहीं लगता कि इसके लिए कोई आउट-ऑफ-द-बॉक्स फ़ंक्शन है। संपादित करें: कोई बात नहीं, मुझे वही मिलता है जो आप कह रहे हैं। एक eval-defunजो पूरे बफर पर काम करता है। ऐसा लगता है कि @JordonBiondo के पास इसके लिए आपका समाधान है।
nispio

नहीं। समस्या का पुनर्मूल्यांकन का अभाव है: defvarकुछ भी नहीं करता है अगर चर का पहले से ही मूल्य है (जैसा कि इसके डॉक्टर कहते हैं:) The optional argument INITVALUE is evaluated, and used to set SYMBOL, only if SYMBOL's value is void.। समस्या यह नहीं है कि defvarडिफ़ॉल्ट मान बदल जाता है और वर्तमान मूल्य नहीं। (defvar a 4) (default-value 'a) (setq a 2) (default-value 'a); फिर सेक्सप के C-x C-eबाद defvar; तब (default-value 'a)C-x C-e, eval-regionऔर defvarसेक्सपैक की तरह डिफ़ॉल्ट मान को परिवर्तित नहीं करते हैं
ड्रू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.