Bisakah fungsi mengakses namanya?

25

Di C ada variabel ajaib __func__yang menyimpan nama fungsi saat ini. Di Bash, ada array yang FUNCNAMEmenyimpan nama semua fungsi di tumpukan panggilan !!!

Apakah ada hal serupa di Emacs Lisp? Atau ada cara sederhana untuk fungsi untuk memiliki akses ke namanya?

Saya belum menemukan jawaban dalam manual Emacs Lisp (bab 12 tentang Fungsi atau indeks variabel dan fungsi dan ..)

phs
sumber
2
Untuk apa sebenarnya Anda membutuhkannya?
lunaryorn
1
Ini bukan variabel ajaib - ini adalah definisi pra-prosesor yang dimasukkan oleh beberapa kompiler.
Sean Allred

Jawaban:

6

Untuk fungsi interaktif, mis. Perintah, Anda bisa menggunakan variabel this-command, atau lebih aman real-this-command,. Perbedaannya adalah bahwa ketika Anda menulis fungsi Anda sendiri, Anda dapat secara eksplisit mengubah nilai this-command. Sebagian besar ini dilakukan untuk memainkan trik-trik yang last-commandberkaitan dengan perintah berulang. Anda seharusnya (tidak bisa?) Melakukan ini dengan real-this-command. Itu akan selalu menjadi nama perintah saat ini.

Saya tidak mengetahui adanya persamaan untuk fungsi non-interaktif.

Tyler
sumber
3
Penting untuk dicatat this-commanddan real-last-commandsama sekali tidak suka __func__. Misalnya jika perintah A memanggil perintah B yang mencetaknya this-commandakan mencetak perintah A, bukan B, juga ini tidak berfungsi sama sekali untuk fungsi.
Jordon Biondo
1
@JordonBiondo Setuju. Saya memang mencatat bahwa itu tidak berfungsi untuk fungsi. phs tidak memberi kita konteksnya, jadi saya kira ini mungkin cukup baik untuk aplikasi nya. Jawaban Anda lebih kuat, tidak ada pertanyaan.
Tyler
22

Jawaban yang diperbarui dengan pencarian waktu ekspansi:

Saya mengatakan dalam jawaban asli saya bahwa mungkin ada cara untuk melakukan ini pada waktu ekspansi / kompilasi alih-alih menjalankan waktu untuk memberikan kinerja yang lebih baik dan saya akhirnya mengimplementasikannya hari ini sambil mengerjakan jawaban saya untuk pertanyaan ini: Bagaimana saya bisa menentukan fungsi mana yang disebut secara interaktif di stack?

Berikut adalah fungsi yang menghasilkan semua frame backtrace saat ini

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

Menggunakan itu dalam makro kita bisa mencari tumpukan ekspansi untuk melihat definisi fungsi apa yang sedang diperluas saat itu dan menempatkan nilai itu tepat di dalam kode.

Berikut adalah fungsi untuk melakukan ekspansi:

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

Ini dia sedang beraksi.

(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'"

Jawaban asli:

Anda dapat menggunakan backtrace-frameuntuk mencari tumpukan sampai Anda melihat bingkai yang mewakili panggilan fungsi langsung dan mendapatkan nama dari itu.

(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

Di sini saya melakukan pencarian nama fungsi saat runtime meskipun mungkin untuk mengimplementasikan ini di makro yang memperluas langsung ke simbol fungsi yang akan lebih performant untuk panggilan ulang dan kompilasi elisp.

Saya menemukan informasi ini ketika mencoba untuk menulis semacam logger fungsi panggilan untuk elisp yang dapat ditemukan di sini dalam bentuk tidak lengkap, tetapi mungkin berguna bagi Anda. https://github.com/jordonbiondo/call-log

Jordon Biondo
sumber
Terima kasih untuk kodenya. Ini menyelesaikan masalah saya dan saya akan menerimanya dalam beberapa hari kecuali seseorang memberi kami semacam "nama-fungsi-nama" variabel yang merupakan bagian dari debugger yang Anda beri petunjuk.
phs
Ngomong-ngomong, tampaknya tidak berfungsi ketika a defunditutup oleh eval-and-compile, yaitu ia kembali nil.
Alexander Shukaev