用词法绑定的let内部的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应该始终在let块末尾调用它之前定义它。不是这样吗?


defun不会按照您的想法去做,它总是创建一个顶层定义。Elisp毕竟不是计划……
wasamasa

2
我知道它会创建一个顶级定义;这就是我想要的。我只希望该顶级定义为闭包。除了此字节编译警告外,它似乎按照我想要的方式工作。
Will Kunkel

Answers:


7

字节编译器决定是否定义函数的方法非常“幼稚”,即使在“显而易见”的情况下也会被愚弄。但是您可以通过一种使编译器了解发生了什么的方式来编写它:

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

当然,更好的办法是改进字节编译器的逻辑:为此欢迎使用补丁程序。


5

要取消字节编译器警告,请尝试在代码之前从第0列(最左侧)开始添加以下内容:

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

C-h f declare-function 告诉你:

declare-function是中的Lisp宏subr.el

(declare-function FN FILE &optional ARGLIST FILEONLY)

在中告知字节编译器FN已定义函数FILE。该FILE参数不由字节编译器使用,而是由 check-declare程序包使用,该程序包检查FILE是否包含的定义FN

FILE可以是Lisp文件(在这种情况下,".el" 扩展名是可选的)或C文件。C文件相对于Emacs "src/"目录展开。使用查找Lisp文件locate-library,如果失败,则将它们相对于包含声明的文件的位置进行扩展。FILE带有"ext:"前缀的A 是外部文件。 check-declare将检查此类文件(如果找到),如果未找到则跳过它们而不会出现错误。

可选ARGLIST指定FN的参数,或者t不指定 FN的参数。省略的ARGLIST默认值为t,不是nil:a nil ARGLIST指定一个空的参数列表,而显式的t ARGLIST则是一个占位符,可以提供后面的arg。

可选的FILEONLYnon- nil意味着check-declare仅检查FILE存在的内容,而不检查其定义的内容FN。这旨在用于check-declare无法识别的功能定义,例如defstruct

请注意,出于的目的check-declare,此语句必须是一行上的第一个非空白。

有关更多信息,请参见Info节点(elisp)Declaring Functions


FILEONLY对于此案,非零论点是否必要?顺便说一句,我会给出相同的答案;-)。
Tobias '18

@Tobias:FILEONLY对我来说,这里似乎并不需要。这似乎表明可以check-declare识别fgdefuns。
提请

@Drew,我想这最后的评论fg唯一有意义的背景下emacs.stackexchange.com/q/39439
菲尔斯

@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,而且,不要指望这种方法有任何优势。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.