Defvarın yeniden değerlendirilmesini nasıl zorlayabilirim?


21

Diyelim ki aşağıdakileri içeren bir Emacs lisp tamponu var:

(defvar foo 1)

Eğer ararsam eval-last-sexpveya eval-buffer, 1 foo'e bağlanırsa. Bu tamponu şu şekilde düzenlerseniz:

(defvar foo 2)

eval-last-sexpve eval-bufferbu satırı tekrar çalıştırmayın foo, yine de 1'dir.

Bu, çok sayıda ifade olduğunda ve özellikle hangi satırların yeniden değerlendirilmediğini izlemem gerektiğinde, bu özellikle zordur.

Sadece (require 'foo)Emacs'ı yeniden başlatmaya baktım ve sonra , daha eski .elc dosyalarını yüklemekten kaçınmak için dikkatli olmalıyım.

Geçerli dosyada tanımlanan değişkenlerin ve fonksiyonların, yeni bir Emacs örneğinde yükleme kodunun yenisiyle aynı durumda olduğundan kesinlikle, pozitif olarak nasıl emin olabilirim?


" Emacs'in kesinlikle yeni bir Emacs örneğinde kodu yeniden yüklemekle aynı olan bir durumda " olduğundan emin olamazsınız . Yalnızca bu ve diğer genel değişkenlerle wrt olduğundan emin olmak istiyorsanız, değerleri kullanarak değerleri kaldırabilir makunboundve ardından arabellekteki kodu yeniden değerlendirebilirsiniz.
Drew,

Tabii ki, (aptal kod) gibi yan etkiler (incf emacs-major-version)tekrar tekrar oluyorsa yaşayabilirim. Çok fazla defvarform içeren kodları kırmakla ilgileniyorum .
Wilfred Hughes,

Yanıtlar:


29

Diğer cevaplarda açıklandığı gibi, bir defvarformu kullanarak değerlendirme eval-last-sexpvarsayılan değeri sıfırlamaz.

Bunun yerine, kullanabilirsiniz eval-defun(bağlı C-M-xiçinde emacs-lisp-modeözel bir istisna olarak istediğiniz davranışı uygular, hangi varsayılan):

Geçerli defun aslında bir çağrıysa defvarveya defcustombu şekilde değerlendirildiğinde, değişken zaten başka bir değere sahip olsa bile, başlangıç ​​değer ifadesini kullanarak değişkeni sıfırlar. (Normalde defvarve defcustomzaten bir tane varsa değeri değiştirmeyin.)


Tamponun tüm içeriğini değerlendirmeniz gerekirse, üst düzey formları sıralı ve eval-defunher birini çağıran bir fonksiyon yazabilirsiniz . Böyle bir şey çalışması gerekir:

(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
Bu cevaptır. Sahte defvarlara veya ilave setlere gerek yoktur. Sadece eval-defunyerine kullanın eval-last-sexp . Tampondaki eval-defunher formu çağıran bir işlev bile yazabilir ve bunun yerine kullanabilirsiniz eval-buffer.
Malabarba

1
@Malabarba Bu mesaj soruya cevap vermekten çok uzak. Tabii eval-defunyerine kullanın eval-last-sexp, ancak zorluk için eval-buffer.
Gilles 'SO- kötü olmaktan'

@Gilles evet, haklısın. @ Malabara'nın tampondaki eval-defunher üst düzey form çağırma fikrinin geçici bir uygulamasını ekledim .
ffevotte

1
defvarİçinde değilse, bu yaklaşım işe yaramaz gibi görünüyor defun. Örnek: (progn (defvar foo "bar")).
Kaushal Modi

2
@kaushalmodi Aldığın son örnekler (düzenli ifadeleri saklayan değişkenler) adaylara çok benziyor defconst(ki her zaman yeniden değerlendiriliyor). Son zamanlarda sonsuz parantez içinde
ffevotte 13.03.2015

5

Diğer yanıtların söylediği gibi, bu defvar'ın çalışma şeklidir, ancak bunun üstesinden gelebilirsiniz, sonuçta bu açıktır.

İsterseniz ve bu süre zarfında defvarın nasıl çalıştığını geçici olarak yeniden tanımlayabilirsiniz, sıfırlamak istediğiniz paketleri yeniden yükleyin.

Vücudun değerlendirilmesi sırasında, defvars değerlerinin her zaman yeniden değerlendirileceği bir makro yazdım.

(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)))))

Örnek Kullanım:

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))

Not: Bu sadece yeniden değerlendirme yaparken sadece docstrings'i görmezden geldiğinden defvarları yeniden değerlendirmek amacıyla kullanılmalıdır. Makroları, dokümanlar için de geçerli olan yeniden değerlendirmeyi desteklemek için değiştirebilirsiniz, ancak bunu size bırakacağım.

Senin durumunda yapabilirsin

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

Ancak elisp yazanların defvar'ın belirtildiği gibi çalışmasını beklediklerini biliyorlar, değeri belirtmek için bazı init fonksiyonlarında tanımlamak ve setq olarak tanımlamak için defvar kullanıyor olabilirler, bu yüzden niyet etmeyeceğiniz değişkenleri bitirebilirsiniz. Bu muhtemelen nadirdir.

Alternatif Uygulama

Bunu kullanarak defvar'ı global olarak yeniden tanımlayabilir ve sembolün değerini, yeni defvar-always-reeval-valuessembolün değerini değiştirerek tanımlanmış olsa bile sembolün değerini INIT-VALUE değişkenine ayarlayıp ayarlamayacağını kontrol edebilirsiniz .

;; 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
Davranışını yeniden tanımlamak defvariyi bir fikir değil emin değilim : defvarbiraz farklı anlambilimsel, birkaç farklı olası kullanımları vardır . Örneğin, makronuzun hesaba katmadığı bir kullanım (defvar SYMBOL), bayt-derleyiciye bir değer ayarlamadan bir değişkenin varlığından bahsetmek için kullanılan formdur.
ffevotte

defvarBir makro ile kesinlikle yeniden tanımlamanız gerekirse, orjinal defvarformu a ile makunbounddeğiştirmek yerine, yerine a ile değiştirmeden daha iyi olurdu setq.
ffevotte

Evet, bu çok kötü bir fikir ve sadece yüklü bir paketin defrelerini sıfırlama tamponunda yeniden değerlendirmek gibi şeyler için kullanılmalı, asla böyle bir şey göndermemelisin.
Jordon Biondo

@Francesco ayrıca makunbound sürümü konusunda haklısın, ben bunu uyguladım ama fikrin dışında kaldım, cevabımı alternatif olarak koydum.
Jordon Biondo

3

Bu defvardeğerlendiriliyor ve tam olarak belirttiğiniz şeyi yapıyor. Ancak, defvaryalnızca bir başlangıç ​​değeri belirler:

İsteğe bağlı argüman INITVALUE değerlendirilir ve sadece SYMBOL değeri geçersiz ise SYMBOL ayarlamak için kullanılır.

Yani istediğinizi elde etmek için, ya yeniden değerlendirmeden önce değişkeni serbest bırakmanız gerekir, örneğin;

(makunbound 'foo)

veya setqdeğeri ayarlamak için kullanın ;

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

Burada bir dokümanı belirtmeniz gerekmiyorsa, defvartamamen atlayabilirsiniz .

Bunu gerçekten kullanmak defvarve otomatik olarak açmak istiyorsanız defvar, geçerli arabellekte (veya bölgedeki veya son seksp, vb.) Çağrıları bulmak için bir işlev yazmanız gerekir ; makunboundher birini arayın ; ve sonra gerçek değerlendirmeyi yap.


eval-bufferİlk önce her şeyi çözecek bir ambalajla oynuyordum , ama @ Francesco'nun cevabı eval-defungerçekten istediğin şeydi.
glucas

1

Aşağıdaki makro, eval-defundestekleyici işlevlerini izleyerek ve belirli bir tamponun bir bölgesini değerlendirmenin artık gerekli olmayacağı şekilde değiştirerek yaratıldı . İlgili iş parçacığında yardıma ihtiyacım vardı Bir ifadeyi dizgeye dönüştürme ve @ Tobias kurtarmaya geldi - bana kusurlu işlevi bir makroya nasıl dönüştürebileceğimi öğretti. eval-sexp-add-defvarsÖncesinde olmamız gerektiğini düşünmüyorum elisp--eval-defun-1, ancak birileri bunun önemli olduğunu düşünüyorsa, lütfen bana bildirin.

;;; 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

Sorun, hattın yeniden değerlendirilmemesi değil. Sorun, defvarbir değişkeni ve varsayılan değerini tanımlamasıdır . Bir değişken zaten mevcutsa, varsayılan değerini değiştirmek geçerli değeri değiştirmez. Ne yazık ki, setqdeğerini güncellemek istediğiniz her değişken için a çalıştırmanız gerekeceğini düşünüyorum .

Bu aşırı olabilir, ancak fooyeni varsayılan değerine kolayca güncelleme yapabilmek istiyorsanız dosyanızı bu şekilde güncelleyebilirsiniz .

(defvar foo 2)
(setq foo 2)

ancak bu, varsayılan değeri kodunuzda iki yerde tutmanızı gerektirir. Bunu da yapabilirsiniz:

(makunbound 'foo)
(defvar foo 2)

ancak foobaşka bir yerde bildirilen bir şans varsa, başa çıkmanız gereken bazı yan etkileri olabilir.


Karmaşık moddaki değişiklikleri test etmeye çalışırken bu zor. Kodu değiştirmemeyi tercih ederim. özel olarak eval-defundavranır defvar, bu yüzden kesinlikle tüm tamponlar için benzer bir şey var?
Wilfred Hughes

@WilfredHughes "Bütün tamponlar için bir şeyler" derken ne demek istediğinizi anlamadım. makunboundGeçerli tamponda bildirilen herhangi bir değişkeni tanımlayan ve sonra yeniden değerlendirecek tek bir işlev mi istiyorsunuz? Kendinizinkini yazabilirsiniz, ancak bunun için kullanıma hazır bir işlev olduğunu sanmıyorum. EDIT: Boşver, ne dediğini anladım. Bir eval-defunbütün tampon üzerinde çalıştığı. @JordonBiondo bunun için sizin çözümünüze benziyor.
nispio

Hayır sorun olduğunu yeniden değerlendirilmesi eksikliği: defvardeğişken zaten bir değeri varsa hiçbir şey yapmaz (kendi doc diyor: The optional argument INITVALUE is evaluated, and used to set SYMBOL, only if SYMBOL's value is void.). Sorun değil o defvarvarsayılan değeri değil, şimdiki değeri değiştirir. (defvar a 4) (default-value 'a) (setq a 2) (default-value 'a); daha sonra C-x C-esonra defvarsexp; o zaman (default-value 'a). C-x C-e, eval-regionVe olduğu gibi defvarsexp do not varsayılan değeri değiştirin.
Drew
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.