0

当您在 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已定义时才会执行。通常是编译时警告的东西突然变成了运行时错误。同样的问题也适用于内置的高阶函数,例如mapcar, apply...

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

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

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

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

4

2 回答 2

1

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

编码

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

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

如果所有的 defun 都用这个宏包装,也许有可能得到你想要的警告。也许defun可以macroleteval-buffer.

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

于 2013-07-23T19:03:43.317 回答
1

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

于 2013-07-24T00:36:24.180 回答