【问题标题】:Emacs Lisp: Byte-compiler warning for undefined functions in apply, mapcarEmacs Lisp:应用程序中未定义函数的字节编译器警告,mapcar
【发布时间】:2013-07-24 13:59:45
【问题描述】:

当您在 emacs lisp 中执行函数调用 (myfunction ...) 时,如果该函数在编译时未知,字节编译器将发出警告。这对自上而下的编程风格有很大帮助,从那时起我就可以愉快地编写了

(defun foo (bar baz)
  (foo-filter-by-functon (lambda (a b) (equal (upcase a) (upcase b)))
   (foo-combine-values bar baz)))

当我编译字节编译器告诉我我还没有定义或拼错两个foo- 函数。

但是,如果 lambda 表达式变得复杂,则需要进行更多重组,例如

(defun foo (bar baz)
  (foo-filter-by-functon 'foo-equal
   (foo-combine-values bar baz)))

现在有一个问题... 'foo-equal 现在是一个符号,并且只有在运行时执行 foo-filter-by-function 时才会执行检查 'foo-equal 是否已定义。通常是编译时警告的东西突然变成了运行时错误。同样的问题也适用于内置的高阶函数,例如mapcarapply...

是否有可能使字节编译器识别,例如mapcar 的第一个参数应该是一个函数,因此,当参数作为符号给出时,检查该符号是否具有有效的函数定义,就像它对显式 (foo-equal ..) 调用所做的那样?

注意:目的是让生产代码更具可读性,因此需要更改每次调用 foo-filter-by-function 的解决方案或其定义中的 hackish 代码是不可接受的解决方案。这种适得其反的解决方案的一个例子是

(defun foo (bar baz)
  (foo-filter-by-functon (lambda (a b) (foo-equal a b)) ... )
   (foo-combine-values bar baz)))

(defun foo (bar baz)
  (foo-filter-by-functon foo-equal
   (foo-combine-values bar baz)))

(defconst foo-equal (lambda (a b) ...)

因为至少在主观上两者都会导致代码可读性差。

【问题讨论】:

    标签: elisp runtime-error compiler-warnings higher-order-functions top-down


    【解决方案1】:

    您想使用#'foo-equal 而不是'foo-equal,以便告诉编译器您不仅仅是在谈论foo-equal 符号,而是在谈论foo-equal 函数。

    【讨论】:

    • 这似乎没有任何改变。如果我编译(defun test-id=025b35ba8670e54d1cf () (add-hook 'bla-bla-hook #'some-function) (mapcar #'some-function '(1 2 3))),我仍然没有收到关于“某些功能”未知的警告。
    • 对,我想你只有在使用 Emacs-24.4 进行字节编译时才会收到警告,早期版本没有捕捉到这种情况。
    【解决方案2】:

    在我看来,您正在触及静态/动态语言问题。

    代码

    (defun foo (bar baz)
      (foo-filter-by-functon 'foo-equal
       (foo-combine-values bar baz)))
    

    是完全合法的 lisp 代码,源于其灵活性。 在某些法律情况下,foo-equal 不需要定义。 我想你的意思是

    (defun foo (bar baz)
      (foo-filter-by-functon #'foo-equal
       (foo-combine-values bar baz)))
    

    它仍然是合法的 lisp 代码。可能有一些情况,虽然较少, 当foo-equal 不需要定义时。

    要点

    foo-filter-by-functon 决定是否调用它的参数, 所以它应该在调用之前检查参数是合乎逻辑的: 也许是这样的:

    (defun-carefully
        `(defun foo-filter-by-function (fun lst)
           (cl-remove-if-not fun lst)))
    

    defun-carefully 是一个定义函数的宏, 并存储在一些它调用它的第一个参数的字典中。 它怎么知道它调用了它的论点?它在同一个字典中查找 cl-remove-if-not 调用它的参数。

    如果所有的 defun 都用这个宏包装,也许有可能得到 到你想要的警告。 也许可以暂时用macrolet重新定义defuneval-buffer 期间。

    仍然有很多工作要做。我希望其他人做到/做到了:)

    【讨论】:

    • 这引发了后续问题。基本上我们需要代码,这会导致函数定义在编译时扩展,但在运行时调用原始函数,即宏 mapcar 执行检查然后扩展为 mapcar 函数调用。当我在找不到阻止 emacs lisp 以宏扩展的无限递归结束之前尝试此类事情时。但肯定的是,确实有很多工作......顺便说一句,它宁愿是byte-compile-from-buffer,我需要用cl-macrolet包装。不过感谢您的提示!
    猜你喜欢
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-12
    • 1970-01-01
    相关资源
    最近更新 更多