[英]Are there function prototypes in Common Lisp?
我已經用通用Lisp編程了一段時間,在使用Lisp的整個經驗中,我還沒有看到任何功能/宏都可以執行類似於C或C ++中的函數原型的功能。
當前,我必須非常注意函數的順序,否則,當我嘗試從另一個函數調用函數時,Lisp說該函數“不存在”,因為它是在文件的后面定義的。 有辦法解決這個問題嗎? 我可以在文件頂部聲明所有函數原型,並在下面聲明完整的定義嗎?
您可以使用Declaim全局聲明某件事具有某種功能類型。 例如,看看在定義foo1調用未定義的baz (在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是不帶參數的函數,並返回一些內容。 如果願意,顯然可以添加更多的類型信息,但這至少可以提供arz和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會從聲明中聲明或取消聲明並靜音未定義的函數警告,但該函數實際上仍然是未定義的。 其他實現(例如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
這也有其警告,因為編譯未定義函數的引用時可能會收到的警告類型可能會有所不同,並且對警告的消聲可能會有所不同。
正如Rainer指出的,如果前向引用在單個編譯單元內,則可以忽略此問題。 但是,如果前向引用越過編譯單元,這將無濟於事。 通常,這表明您的代碼沒有很好的分層。 低級別的代碼可以調用更高級別的代碼? 嗯,人們會說底層代碼為高層代碼提供了一個鈎子。
也就是說,我當然已經看到並編寫了存在此問題的代碼。 意大利面條代碼,好極了! 當您開始將巨大的源文件分解為較小的文件時,可能會出現這種情況。 編譯單元通常是單個文件。 但是看看with-compilation-unit。 我不記得,盡管asdf無法提供便捷的訪問。
我不知道Joshua使用提供聲明的解決方案是否可以在所有CL實現中使用。 我的記憶是,很多年前我不得不解決這個問題時,我們不得不實施一些更原始的東西 ,我們將對該函數進行定義,然后共同研究一種抑制定義警告的方法。
毫無疑問,可以使用cl-launch來查看Joshua的解決方案是否適用於各種實現。
在定義任何方法之前,可以將其定義為通用函數。 所以,如果你寫
(defgeneric foo(xyz))
那么任何調用FOO的函數都將看到一個已定義的函數(盡管該函數沒有任何方法)。 該函數的主體隨后可以作為方法添加
(defmethod foo(xyz);;函數體...)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.