Le funzioni possono accedere al loro nome?


25

In C c'è la variabile magica __func__che contiene il nome della funzione corrente. In Bash, c'è un array FUNCNAMEche contiene i nomi di tutte le funzioni nello stack chiamante !!!

C'è qualcosa di simile in Emacs Lisp? O un modo semplice per una funzione di avere accesso al suo nome?

Non ho trovato alcuna risposta nel manuale di Emacs Lisp (capitolo 12 su Funzioni o indice di variabili e funzioni e ...)


2
A cosa ti serve davvero?
lunaryorn,

1
Non è esattamente una variabile magica, è una definizione pre-processore inserita da alcuni compilatori.
Sean Allred,

Risposte:


6

Per le funzioni interattive, cioè, comandi, è possibile utilizzare la variabile this-command, o più sicuro, real-this-command. La differenza è che quando si scrivono le proprie funzioni, è possibile modificare esplicitamente il valore di this-command. Principalmente questo viene fatto per giocare brutti scherzi last-commandrelativi ai comandi ripetuti. Non dovresti (non puoi?) Farlo con real-this-command. Sarà sempre il nome del comando corrente.

Non sono a conoscenza di un equivalente per funzioni non interattive.


3
E 'importante notare che this-commande real-last-commandnon sono affatto come __func__. Ad esempio, se il comando A chiama il comando B che this-commandlo stampa stamperà il comando A, non B, anche questo non funziona affatto per le funzioni.
Jordon Biondo,

1
@JordonBiondo Concordato. Ho notato che non funziona per le funzioni. phs non ci ha fornito il suo contesto, quindi ho immaginato che questo potesse essere abbastanza buono per la sua applicazione. La tua risposta è più solida, nessuna domanda.
Tyler,

22

Risposta aggiornata con ricerca del tempo di espansione:

Nella mia risposta originale ho detto che potrebbe esserci un modo per farlo in fase di espansione / compilazione anziché in fase di esecuzione per fornire prestazioni migliori e alla fine l'ho implementato oggi mentre lavoravo sulla mia risposta per questa domanda: Come posso determinare quale funzione era chiamato interattivamente nello stack?

Ecco una funzione che produce tutti i frame di backtrace correnti

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

Usandolo in una macro possiamo cercare lo stack di espansione per vedere quale definizione di funzione viene espansa in quel momento e mettere quel valore nel codice.

Ecco la funzione per fare l'espansione:

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

Qui è in azione.

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

Risposta originale:

Puoi usare backtrace-frameper cercare lo stack finché non vedi un frame che rappresenta una chiamata di funzione diretta e ne ottieni il nome.

(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

Qui sto eseguendo la ricerca del nome della funzione in fase di runtime sebbene sia probabilmente possibile implementarlo in una macro che si espande direttamente nel simbolo della funzione che sarebbe più performante per le chiamate ripetute e l'elisp compilato.

Ho trovato queste informazioni mentre cercavo di scrivere una sorta di logger di chiamate di funzione per elisp che può essere trovato qui nella sua forma incompleta, ma potrebbe esserti utile. https://github.com/jordonbiondo/call-log


Grazie per il codice Questo risolve il mio problema e lo accetterò tra qualche giorno a meno che qualcuno non ci dia una sorta di variabile "nome-funzione-corrente" che fa parte del debugger a cui accenni.
phs,

A proposito, non sembra funzionare quando defunè racchiuso da un eval-and-compile, cioè ritorna nil.
Alexander Shukaev,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.