関数は名前にアクセスできますか?


25

Cには__func__、現在の関数名を保持するマジック変数があります。BashにはFUNCNAME、呼び出しスタック内のすべての関数の名前を保持する配列があります!!!

Emacs Lispに同様のものがありますか?または、関数がその名前にアクセスする簡単な方法はありますか?

Emacs Lispマニュアル(関数の章または変数と関数のインデックスの章12および..)に答えが見つかりませんでした。


2
実際に何が必要ですか?
lunaryorn

1
正確な魔法の変数ではありません。一部のコンパイラーによって挿入されるプリプロセッサー定義です。
ショーンオールレッド

回答:


6

対話機能、つまりコマンドの場合、変数this-command、またはより安全なを使用できますreal-this-command。違いは、独自の関数を作成するときに、の値を明示的に変更できることですthis-command。ほとんどの場合、これはlast-command繰り返しコマンドに関連するトリックをプレイするために行われます。でこれを行うべきではありません(できませんか?)real-this-command。常に現在のコマンドの名前になります。

非対話型関数に相当するものを知りません。


3
これは、ことに注意することが重要だthis-commandreal-last-commandのように、すべてではありません__func__。たとえば、コマンドAがコマンドBを呼び出して印刷this-commandする場合、コマンドAはB ではなくコマンドAを印刷しますが、これも機能に対してはまったく機能しません。
ジョーダンビオンド

1
@jordonBiondo同意しました。関数では機能しないことに注意しました。phsは彼のコンテキストを教えてくれなかったので、これで彼のアプリケーションには十分かもしれないと思いました。あなたの答えはより堅牢で、疑問の余地はありません。
タイラー

22

展開時間のルックアップで更新された回答:

私はそこに、より良い性能を与えるために、拡張/コンパイル時の代わりに、実行時にこれを行うための方法であることと、この質問に対する私の答えに取り組んでいる間、私はようやく今日という実装されていることを私のオリジナルの答えで述べている:どのように私はあった機能を決定することができますスタックでインタラクティブに呼び出されますか?

以下は、現在のすべてのバックトレースフレームを生成する関数です。

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

これをマクロで使用すると、展開スタックを検索して、その時点でどの関数定義が展開されているかを確認し、その値をコード内に配置できます。

展開を行う関数は次のとおりです。

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

ここで動作しています。

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

元の回答:

を使用backtrace-frameして、直接関数呼び出しを表すフレームが表示されるまでスタックを検索し、そこから名前を取得できます。

(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

ここでは、実行時に関数名の検索を行っていますが、繰り返し呼び出しとコンパイルされたelispのパフォーマンスが高い関数シンボルに直接展開するマクロでこれを実装することはおそらく可能です。

この情報は、elispの関数呼び出しロガーのようなものを記述しようとするときに見つけました。不完全な形式でここにありますが、役に立つかもしれません。https://github.com/jordonbiondo/call-log


コードをありがとう。これは私の問題を解決し、誰かが示唆したデバッガーの一部である「current-function-name」変数のようなものを私たちに与えない限り、数日でそれを受け入れます。
phs 14年

ところで、defunがで囲まれている場合は動作しないようです。eval-and-compileつまり、が返されますnil
アレクサンダーシュカエフ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.