ฟังก์ชั่นสามารถเข้าถึงชื่อของพวกเขา?


25

ใน C มีตัวแปรเวทย์มนตร์__func__ที่เก็บชื่อฟังก์ชั่นปัจจุบัน ใน Bash มีอาร์เรย์ที่FUNCNAMEถือชื่อของฟังก์ชั่นทั้งหมดในสแตกการโทร !!!

มีสิ่งที่คล้ายกันใน Emacs Lisp หรือไม่? หรือวิธีง่ายๆสำหรับฟังก์ชั่นในการเข้าถึงชื่อหรือไม่?

ฉันไม่พบคำตอบในคู่มือ Emacs Lisp (บทที่ 12 เกี่ยวกับฟังก์ชั่นหรือดัชนีของตัวแปรและฟังก์ชั่นและ .. )


2
คุณต้องการอะไรจริงๆ
Lunaryorn

1
มันไม่ได้เป็นตัวแปรวิเศษ - มันเป็นคำจำกัดความของตัวประมวลผลล่วงหน้าที่ใส่โดยคอมไพเลอร์บางตัว
ฌอน Allred

คำตอบ:


6

สำหรับฟังก์ชั่นการโต้ตอบคือคำสั่งที่คุณสามารถใช้ตัวแปรหรือที่ปลอดภัยthis-command ความแตกต่างที่ว่าเมื่อคุณเขียนฟังก์ชั่นของคุณเองคุณอย่างชัดเจนสามารถเปลี่ยนค่าของreal-this-command this-commandส่วนใหญ่จะทำเพื่อเล่นลูกเล่นlast-commandที่เกี่ยวข้องกับคำสั่งซ้ำ คุณไม่ควร (ไม่สามารถ?) real-this-commandทำเช่นนี้กับ มันจะเป็นชื่อของคำสั่งปัจจุบันเสมอ

ฉันไม่ได้ตระหนักถึงสิ่งที่เทียบเท่ากับฟังก์ชั่นที่ไม่ใช่แบบโต้ตอบ


3
มันเป็นสิ่งสำคัญที่จะทราบว่าthis-commandและไม่ได้ที่ทุกคนชอบreal-last-command __func__ตัวอย่างเช่นถ้าคำสั่ง A คำสั่งเรียก B ซึ่งพิมพ์this-commandมันจะพิมพ์คำสั่ง A ไม่ใช่ B เช่นนี้จะไม่ทำงานเลยสำหรับฟังก์ชั่น
Jordon Biondo

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

การใช้สิ่งนั้นในแมโครเราสามารถค้นหา stack stack เพื่อดูว่านิยามฟังก์ชั่นใดถูกขยายในเวลาและทำให้ค่านั้นถูกต้องในโค้ด

นี่คือฟังก์ชั่นเพื่อทำการขยาย:

(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

โดยวิธีการที่มันดูเหมือนจะไม่ทำงานเมื่อdefunถูกล้อมรอบด้วยeval-and-compileคือมันกลับnilมา
Alexander Shukaev
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.