我使用 common lisp 编程已经有一段时间了,在我使用 lisp 的整个过程中,我还没有看到任何函数/宏的行为类似于 C 或 C++ 中的函数原型(prototype)。
目前我必须非常小心我的函数的顺序,否则,当我尝试从另一个函数调用一个函数时,Lisp 会说该函数“不存在”,因为它在文件的后面定义。有办法解决这个问题吗?我可以在文件顶部声明我所有的函数原型(prototype),并在下面声明完整的定义吗?
最佳答案
Declaim和 Proclaim
您可以使用 declaim全局声明某个事物具有某种功能类型。例如,如果您定义调用未定义的 baz 的 foo1(在 SBCL 中),请先看看会发生什么:
CL-USER> (defun foo1 ()
(baz))
; in: DEFUN FOO1
; (BAZ)
;
; caught STYLE-WARNING:
; undefined function: BAZ
;
; compilation unit finished
; Undefined function:
; BAZ
; caught 1 STYLE-WARNING condition
FOO1
现在,让我们添加一个声明,说明 baz 是一个没有参数的函数,并返回一些东西。如果您愿意,您显然可以添加更多类型信息,但这至少会提供 baz 是一个函数的特性和知识。
CL-USER> (declaim (ftype (function () t) baz))
; No value
现在,当您定义同时调用 baz 的 foo2 时,您将不会收到任何警告:
CL-USER> (defun foo2 ()
(baz))
FOO2
Declaim 是一个宏,但是如果你需要能够在运行时生成其中的一些东西,你可以使用 proclaim , 这是一个函数。例如,
CL-USER> (dolist (f '(square cube))
(proclaim `(ftype (function (number) number) ,f)))
NIL
CL-USER> (defun add-square-and-cube (x y)
(+ (square x) (cube y)))
ADD-SQUARE-AND-CUBE
也就是说,这不是很惯用 Common Lisp。更常见的做法是将您需要的代码放入一个文件,然后编译该文件并加载它。如果由于某种原因无法做到这一点,这也行得通,但值得考虑加载代码的其他选项(如果可用)。
消音警告
同样值得注意的是,虽然 SBCL 会从 proclaim 或 declaim 中获取提示并使未定义的函数警告静音,但该函数实际上仍然是未定义的。其他实现(例如 CLISP)仍将发出有关未定义函数的警告。
我真的不推荐以下方法,因为警告的存在是有原因的,但是您可以选择在评估代码时消除警告。例如,在 CLISP 中,当我们使用未定义的函数进行编译时会收到警告:
CL-USER> (compile nil (lambda () (baz)))
WARNING: Function BAZ is not defined
#<COMPILED-FUNCTION NIL>
1
1
不过,我们可以绑定(bind)一个处理程序来消除在评估表单时出现的任何警告:
CL-USER> (handler-bind ((warning
(lambda (x)
(muffle-warning x))))
(compile nil (lambda () (baz))))
#<COMPILED-FUNCTION NIL>
1
1
这也有一些注意事项,因为编译对未定义函数的引用时可能收到的警告类型可能会有所不同,警告的消音效果也可能会有所不同。
关于lisp - Common Lisp 中有函数原型(prototype)吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25586889/