Common Lisp中是否有函数原型?

时间:2014-08-30 21:26:52

标签: lisp common-lisp function-prototypes

我已经在普通的lisp中编程了一段时间,在我使用lisp的经验中,我还没有看到任何与C或C ++中的函数原型类似的函数/宏。

目前我必须非常小心我的函数的排序,否则,当我尝试从另一个函数调用函数时,Lisp说函数“不存在”,因为它在文件的后面定义。有办法解决这个问题吗?我可以在文件顶部声明我的所有函数原型,以及下面的完整定义吗?

3 个答案:

答案 0 :(得分:12)

DeclaimProclaim

您可以使用declaim全局声明某个东西具有某种功能类型。例如,如果您定义调用undefined 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 是一个功能的arity和知识。

CL-USER> (declaim (ftype (function () t) baz))
; No value

现在,当您定义 foo2 并且还调用 baz 时,您将不会收到任何警告:

CL-USER> (defun foo2 ()
           (baz))
FOO2

声明是一个宏,但如果你需要能够在运行时生成其中的一些内容,可以使用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。将所需代码放入文件然后编译该文件并加载它会更常见。如果由于某种原因无法实现,则可以使用,但如果可以使用其他加载代码的选项,则值得考虑。

Muffling警告

值得注意的是,虽然SBCL将从proclaim中获取提示或声明并静默未定义的函数警告,但该函数实际上仍未定义。其他实现(例如,CLISP)仍将发出关于未定义函数的警告。

我不建议采用以下方法,因为警告是有原因的,但是可以选择在评估代码时消除警告。例如,在CLISP中,当我们使用未定义的函数进行编译时会收到警告:

CL-USER> (compile nil (lambda () (baz)))
WARNING: Function BAZ is not defined
#<COMPILED-FUNCTION NIL>
1
1

我们可以绑定一个处理程序,它将消除评估表单时发生的任何警告,但是:

CL-USER> (handler-bind ((warning
                         (lambda (x)
                           (muffle-warning x))))
           (compile nil (lambda () (baz))))
#<COMPILED-FUNCTION NIL>
1
1

这也有它的注意事项,因为编译对未定义函数的引用可能会出现的警告类型可能会有所不同,警告的消音可能会有所不同。

答案 1 :(得分:4)

正如Rainer所指出的,如果前向引用位于单个编译单元中,则可以忽略此问题。但是,如果前向引用跨越编译单元,那将无济于事。通常这表示您的代码分层不佳。低级代码调用更高级别的代码?好吧,人们会说低级代码为高级代码提供了一个钩子。

那说我当然看到并编写了有这个问题的代码。意大利面条代码,百胜!当您开始将大型源文件分解为较小的源文件时,就会出现这种情编译单元通常是单个文件。但是看看with-compilation-unit。我不记得asdf虽然不提供简单的访问权。

我不知道Joshua使用提供声明的解决方案是否适用于所有CL实现。我的记忆是,当我多年前必须解决这个问题时,我们必须实现something more crude,我们会在定义中赋予函数一个立场,然后将一种方法组合在一起来抑制定义警告。

毫无疑问cl-launch可以用来看看Joshua的解决方案是否适用于各种实现。

答案 2 :(得分:0)

在定义任何方法之前,您可以将某些内容定义为泛型函数。所以,如果你写的话

(defgeneric foo(x y z))

然后任何调用FOO的函数都会看到一个已定义的函数(尽管没有任何方法)。然后可以将函数体添加为方法

(defmethod foo(x y z)    ;;功能的主体    ...)