Defun ภายในให้กับคำศัพท์ผูกพันให้เตือนไบต์รวบรวม "ฟังก์ชั่นไม่เป็นที่รู้จักที่จะกำหนด"


13

ฉันต้องการได้รับผลกระทบของตัวแปรคงที่โดยใช้defunด้านในของletกับการผูกศัพท์เพื่อสร้างการปิด อย่างไรก็ตามเมื่อทำการคอมไพล์ไฟล์ฉันได้รับคำเตือน ฉันกำลังทำสิ่งผิดปกติหรือไม่ถ้าไม่มีวิธีระงับคำเตือนนี้หรือไม่?

ฉันสร้าง MCVE แล้ว:

;; -*- lexical-binding: t -*-

(let ((count 0))
  (defun increase-count ()
    (interactive)
    (setq count (1+ count))
    (message "Count is: %d" count))

  ;; The warning happens here.
  (increase-count))

รหัสทำงานได้ตามที่คาดไว้: ฟังก์ชันจะincrease-countพิมพ์ "Count is: n" โดยที่ n เพิ่มขึ้นทุกครั้งที่เรียกใช้ อย่างไรก็ตามเมื่อคอมไพล์ไฟล์นี้ฉันได้รับคำเตือนต่อไปนี้:

In end of data:
mcve.el:11:1:Warning: the function ‘increase-count’ is not known to be
    defined.

ดูเหมือนว่าฉันincrease-countควรกำหนดไว้เสมอก่อนที่จะถูกเรียกที่ท้ายบล็อก นี่ไม่ใช่กรณีหรือไม่


defunไม่ได้ทำสิ่งที่คุณคิดว่ามันทำมันจะสร้างคำนิยามระดับบนสุดเสมอ Elisp นั้นไม่ใช่ Scheme ทั้งหมด ...
wasamasa

2
ฉันรู้ว่ามันสร้างคำนิยามระดับบนสุด; นั่นคือสิ่งที่ฉันต้องการ. ฉันแค่อยากให้คำจำกัดความระดับสูงสุดนั้นปิดตัวลง ดูเหมือนว่าจะทำงานในแบบที่ฉันต้องการยกเว้นคำเตือนการรวบรวมไบต์นี้
Will Kunkel

คำตอบ:


7

วิธีของคอมไพเลอร์ไบต์ในการตัดสินใจว่าฟังก์ชันจะถูกกำหนดหรือไม่นั้น "ไร้เดียงสา" มากและถูกหลอกแม้ในกรณี "ชัดเจน" ของคุณ แต่คุณสามารถเขียนในวิธีที่ทำให้คอมไพเลอร์เข้าใจว่าเกิดอะไรขึ้น:

(defalias 'increase-count
  (let ((count 0))
    (lambda ()
      (interactive)
      (setq count (1+ count))
      (message "Count is: %d" count))))

แน่นอนยิ่งกว่านั้นก็คือการปรับปรุงตรรกะของคอมไพเลอร์ไบต์: แพตช์ต้อนรับสิ่งนั้น


5

หากต้องการระงับการเตือน byte-compiler ลองเพิ่มสิ่งนี้ก่อนรหัสของคุณเริ่มต้นในคอลัมน์ 0 (ซ้ายสุด):

(declare-function increase-count "your-file-name.el")

C-h f declare-function บอกคุณ:

declare-functionsubr.elเป็นแมโครเสียงกระเพื่อมใน

(declare-function FN FILE &optional ARGLIST FILEONLY)

บอกไบต์คอมไพเลอร์ที่ฟังก์ชั่นที่มีการกำหนดในFN โต้แย้งไม่ได้ถูกใช้โดยไบต์คอมไพเลอร์ แต่โดย แพคเกจซึ่งการตรวจสอบว่าไฟล์ที่มีความหมายสำหรับFILEFILEcheck-declareFN

FILEสามารถเป็นได้ทั้งไฟล์เสียงกระเพื่อม (ซึ่งในกรณีนี้".el" ส่วนขยายเป็นตัวเลือก) หรือไฟล์ C ไฟล์ C ถูกขยายสัมพันธ์กับ"src/"ไดเร็กทอรีEmacs ไฟล์เสียงกระเพื่อมมีการค้นหาโดยใช้locate-libraryและหากล้มเหลวพวกเขาจะถูกขยายสัมพันธ์กับตำแหน่งของไฟล์ที่มีการประกาศ A FILEพร้อม"ext:"คำนำหน้าเป็นไฟล์ภายนอก check-declareจะตรวจสอบไฟล์ดังกล่าวหากพบและข้ามไฟล์โดยไม่มีข้อผิดพลาดหากไม่พบ

ตัวเลือกARGLISTระบุFN's ข้อโต้แย้งหรือเป็นtไปไม่ได้ระบุ FNข้อโต้แย้งของ ARGLISTค่าเริ่มต้นที่ถูกละเว้นไปtไม่ใช่nil: a nil ARGLISTระบุรายการอาร์กิวเมนต์ที่ว่างเปล่าและชัดแจ้งt ARGLISTเป็นตัวยึดตำแหน่งที่อนุญาตให้มีการจัดหา ARG ในภายหลัง

เป็นตัวเลือกFILEONLYที่ไม่ได้nilหมายความว่าcheck-declareจะตรวจสอบเพียงอย่างเดียวที่มีอยู่ไม่ว่าจะกำหนดFILE FNนี้มีไว้สำหรับคำจำกัดความของฟังก์ชั่นที่ไม่รู้จักเช่นcheck-declaredefstruct

โปรดทราบว่าสำหรับวัตถุประสงค์ของcheck-declareคำสั่งนี้จะต้องไม่ใช่ช่องว่างแรกในบรรทัด

(elisp)Declaring Functionsสำหรับข้อมูลเพิ่มเติมโปรดดูที่ข้อมูลโหนด


FILEONLYอาร์กิวเมนต์ที่ไม่มีค่าศูนย์จำเป็นสำหรับคดีในมือหรือไม่? BTW ฉันจะได้รับคำตอบเดียวกัน ;-)
Tobias

@Tobias: FILEONLYดูเหมือนจะไม่ต้องการที่นี่สำหรับฉัน ซึ่งดูเหมือนว่าจะบ่งบอกว่าcheck-declareรับรู้fและgdefuns
Drew

@ ดึงฉันคิดว่าความคิดเห็นล่าสุดเกี่ยวกับfและเหมาะสมgเท่านั้นในบริบทของemacs.stackexchange.com/q/39439 ?
Phils

@phils: ใช่ฉันตั้งใจจะพูดแบบนี้: FILEONLYดูเหมือนจะไม่จำเป็นสำหรับฉัน ซึ่งดูเหมือนว่าจะบ่งบอกว่าcheck-declareรับรู้ถึงการincrease-countdefun ;-)
ดึง

3

ฉันเชื่อว่าการวางคำจำกัดความที่เป็นปัญหาภายในeval-and-compileนั้นจะให้ผลลัพธ์ที่ผิวเผินเช่นเดียวกับคำตอบที่ถูกต้องของ Stefan :

(eval-and-compile
  (let ((count 0))
    (defun increase-count ()
      (interactive)
      (setq count (1+ count))
      (message "Count is: %d" count))))

อย่างไรก็ตามฉันแทบจะไม่คุ้นเคยกับรายละเอียดปลีกย่อยของการใช้eval-and-compileและยิ่งกว่านั้นอย่าคาดหวังว่าวิธีการนี้จะเหนือกว่าในทางใดทางหนึ่ง

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