İşlevler isimlerine erişebilir mi?


25

C'de __func__o anki fonksiyon adını tutan sihirli değişken vardır. Bash'de FUNCNAMEçağıran yığındaki tüm fonksiyonların isimlerini içeren bir dizi var !!!

Emacs Lisp'te de benzer bir şey var mı? Veya bir işlevin adına erişebilmesi için herhangi bir basit yol var mı?

Emacs Lisp el kitabında herhangi bir cevap bulamadım (İşlevler veya değişkenler ve işlevler dizini bölüm 12 ve ..)


2
Buna gerçekten ne için ihtiyacın var?
lunaryorn

1
Bu tam bir sihirli değişken değil - bazı derleyiciler tarafından eklenen bir ön işlemci tanımı .
Sean Allred,

Yanıtlar:


6

Etkileşimli işlevler, yani komutlar için değişkeni this-commandveya daha güvenli kullanabilirsiniz real-this-command. Aradaki fark, kendi fonksiyonlarınızı yazdığınızda, değerini açıkça değiştirebilirsiniz this-command. Çoğunlukla bu, last-commandtekrar eden komutlarla ilgili hileler yapmak için yapılır . Bunu yapmamalısın (yapamaz mısın?) real-this-command. Her zaman geçerli komutun adı olacaktır.

Etkileşimli olmayan işlevler için bir eşdeğerin farkında değilim.


3
Bunu not etmek önemlidir this-commandve real-last-commandhiç de öyle değildir __func__. Örneğin, eğer A komutu this-commandonu basan B'yi çağırırsa , A komutunu yazmaz, B'yi değil, bu da fonksiyonlar için hiç işe yaramaz.
Jordon Biondo,

1
@JordonBiondo Anlaşıldı. Fonksiyonlar için işe yaramadığını not ettim. phs bize bağlamını vermedi, bu yüzden bunun başvurusu için yeterince iyi olabileceğini tahmin ettim. Cevabınız daha sağlam, soru yok.
Tyler

22

Genişletme süresi aramasıyla güncellenmiş yanıt:

Orijinal cevabımda, daha iyi performans vermek için çalışma zamanı yerine genişleme / derleme zamanında bunu yapmanın bir yolu olabileceğini söyledim ve nihayet bu soruyu yanıtlamada çalışırken bugün uyguladım: Hangi fonksiyonun ne olduğunu nasıl belirleyebilirim etkileşimli yığında çağırdı?

İşte tüm mevcut backtrace çerçevelerini veren bir fonksiyon

(defun call-stack ()
  "Return the current call stack frames."
  (let ((frames)
        (frame)
        (index 5))
    (while (setq frame (backtrace-frame index))
      (push frame frames)
      (incf index))
    (remove-if-not 'car frames)))

Bunu bir makroda kullanarak, o sırada hangi işlev tanımının genişletildiğini görmek için genişletme yığınını arayabilir ve bu değeri doğrudan koda koyabiliriz.

Genişletme yapma işlevi:

(defmacro compile-time-function-name ()
  "Get the name of calling function at expansion time."
  (symbol-name
   (cadadr
    (third
     (find-if (lambda (frame) (ignore-errors (equal (car (third frame)) 'defalias)))
              (reverse (call-stack)))))))

İşte eylemde.

(defun my-test-function ()
  (message "This function is named '%s'" (compile-time-function-name)))

(symbol-function 'my-test-function)
;; you can see the function body contains the name, not a lookup
(lambda nil (message "This function is named '%s'" "my-test-function"))

(my-test-function)
;; results in:
"This function is named 'my-test-function'"

Orijinal cevap:

backtrace-frameDoğrudan bir işlev çağrısını temsil eden kareyi görene kadar yığını aramak için kullanabilirsiniz ve bu adın adını alın.

(defun get-current-func-name ()
  "Get the symbol of the function this function is called from."
  ;; 5 is the magic number that makes us look 
  ;; above this function
  (let* ((index 5)
         (frame (backtrace-frame index)))
    ;; from what I can tell, top level function call frames
    ;; start with t and the second value is the symbol of the function
    (while (not (equal t (first frame)))
      (setq frame (backtrace-frame (incf index))))
    (second frame)))

(defun my-function ()
  ;; here's the call inside my-function
  (when t (progn (or (and (get-current-func-name))))))

(defun my-other-function ()
  ;; we should expect the return value of this function
  ;; to be the return value of my-function which is the
  ;; symbol my-function
  (my-function))

(my-other-function) ;; => 'my-function

Burada, çalışma zamanı işlev adı araması yapıyorum, ancak bunu doğrudan çağrılar ve derlenmiş elisp için daha performans gösteren doğrudan işlev sembolüne genişleten bir makroda uygulamak mümkün olabilir.

Bu bilgiyi elisp için eksik formda bulunan bir tür işlev çağrısı günlüğü yazmaya çalışırken buldum, ancak sizin için yararlı olabilir. https://github.com/jordonbiondo/call-log


Kod için teşekkürler. Bu benim sorunumu çözdü ve birisi bize bahsettiğiniz hata ayıklayıcının bir parçası olan bir tür "current-function-name" değişkeni vermediği sürece birkaç gün içinde kabul edeceğim .
phs

Bu arada, a defuntarafından çevrildiği zaman işe yaramadı eval-and-compile, yani geri dönüyor nil.
Alexander Shukaev
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.