Defun bên trong let with ràng buộc từ vựng đưa ra cảnh báo biên dịch byte, chức năng không được xác định là xác định


13

Tôi muốn có được hiệu ứng của một biến tĩnh bằng cách sử dụng defunbên trong letvới ràng buộc từ vựng để tạo ra một bao đóng. Tuy nhiên, khi biên dịch byte tệp, tôi nhận được cảnh báo. Tôi đang làm gì đó sai, hoặc nếu không, có cách nào để ngăn chặn cảnh báo này?

Tôi đã tạo một 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))

Mã này hoạt động như mong đợi: hàm increase-countin ra "Đếm là: n" trong đó n tăng mỗi lần nó được gọi. Tuy nhiên, khi biên dịch byte tệp này, tôi nhận được cảnh báo sau:

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

Đối với tôi, nó increase-countluôn luôn phải được xác định trước khi nó được gọi ở cuối khối let. đây không phải là trường hợp?


defunkhông làm những gì bạn nghĩ nó làm, nó luôn tạo ra một định nghĩa cấp cao nhất. Elisp sau tất cả không phải là Đề án ...
wasamasa

2
Tôi biết rằng nó tạo ra một định nghĩa cấp cao nhất; đó là điều tôi muốn. Tôi chỉ muốn định nghĩa cấp cao nhất là đóng cửa. Nó dường như hoạt động theo cách tôi muốn, ngoại trừ cảnh báo biên dịch byte này.
Will Kunkel

Câu trả lời:


7

Cách của trình biên dịch byte để quyết định xem một hàm sẽ được xác định hay không là rất "ngây thơ" và bị đánh lừa ngay cả trong trường hợp "hiển nhiên" của bạn. Nhưng bạn có thể viết nó theo cách cho phép trình biên dịch hiểu điều gì xảy ra:

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

Tất nhiên, thậm chí tốt hơn sẽ là cải thiện logic của trình biên dịch byte: các bản vá được chào đón cho điều đó.


5

Để loại bỏ cảnh báo trình biên dịch byte, hãy thử thêm điều này trước mã của bạn, bắt đầu từ cột 0 (ngoài cùng bên trái):

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

C-h f declare-function nói với bạn:

declare-functionlà một macro Lisp trong subr.el.

(declare-function FN FILE &optional ARGLIST FILEONLY)

Nói cho trình biên dịch byte rằng hàm FNđược định nghĩa, trong FILE. Đối FILEsố không được sử dụng bởi trình biên dịch byte, nhưng bởi check-declaregói, kiểm tra FILE có chứa định nghĩa cho FN.

FILEcó thể là tệp Lisp (trong trường hợp đó là ".el" phần mở rộng là tùy chọn) hoặc tệp C. Các tệp C được mở rộng liên quan đến "src/"thư mục Emacs . Các tệp Lisp được tìm kiếm để sử dụng locate-libraryvà nếu thất bại, chúng được mở rộng liên quan đến vị trí của tệp chứa khai báo. A FILEvới "ext:"tiền tố là một tập tin bên ngoài. check-declaresẽ kiểm tra các tệp như vậy nếu chúng được tìm thấy và bỏ qua chúng mà không gặp lỗi nếu không.

Tùy chọn ARGLISTchỉ định FNđối số hoặc là tkhông chỉ định FNđối số. Một ARGLISTmặc định được bỏ qua t, không nil: nil ARGLISTchỉ định một danh sách đối số trống và rõ ràng t ARGLISTlà một trình giữ chỗ cho phép cung cấp một đối số sau này.

Tùy chọn FILEONLYkhông nilcó nghĩa rằng check-declarechỉ sẽ kiểm tra rằng FILEtồn tại, không phải là nó định nghĩa FN. Điều này dành cho các định nghĩa hàm check-declarekhông nhận ra, ví dụ , defstruct.

Lưu ý rằng cho các mục đích của check-declare, tuyên bố này phải là khoảng trắng đầu tiên trên một dòng.

Để biết thêm thông tin, xem nút Thông tin (elisp)Declaring Functions.


Là một FILEONLYđối số không cần thiết cho trường hợp trong tầm tay? BTW, tôi sẽ có câu trả lời tương tự ;-).
Tobias

@Tobias: FILEONLYdường như không cần thiết ở đây, đối với tôi. Mà dường như chỉ ra rằng check-declarecông nhận fgdefun.
Drew

@Drew, tôi nghĩ rằng nhận xét cuối cùng về fgchỉ có ý nghĩa trong bối cảnh của emacs.stackexchange.com/q/39439 ?
phils

@phils: Vâng, tôi muốn nói điều này: FILEONLYdường như không cần thiết ở đây, đối với tôi. Mà dường như chỉ ra rằng check-declarecông nhận increase-countdefun. ;-)
Drew

3

Tôi tin rằng việc đặt các định nghĩa trong câu hỏi trong vòng eval-and-compilecũng sẽ hời hợt đạt được kết quả tương tự như trong Stefan của câu trả lời đúng :

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

Tôi, tuy nhiên, hầu như không quen thuộc với sự tinh tế của việc sử dụng eval-and-compilevà, hơn nữa, không hy vọng phương pháp này sẽ vượt trội hơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.