2016-11-28 10 views
3

次のコードサンプルで、SBCLでf2についての未定義の関数警告が表示されます。 警告を避けるために、C言語のように最初にf2を宣言することは可能でしょうか? 私はグーグルで、手がかりはありません。共通のlispで定義する前に関数を宣言するには?

(defun f() 
    (print (f2))) 

(defun f2() 
    (print "f2")) 

答えて

5

あなたは例えば、単一compilation unitでそれを定義する前に、同じファイルを関数を使用する場合は、コンパイラが未定義の関数(プレーンloadまだかもしれない、文句はありませんので、最初にあなたのコードをコンパイルするには!そうでなければ)

、次のことができdeclaimftypef2は引数を受け付けないことを意味

(declaim (ftype (function() t) f2) 

タイプtの単一のvalueを返します。

しかし、定義が既にロードされている間に関数を使用する場所でファイルをコンパイルする方がはるかに意味があります。ユーザはコンパイル時にコンパイラがすべての関数の定義を持つように依存関係を指定することで、asdfをLisp特有のmake(1)として使うことができます(そしてそうすべきです)。

+0

私はこれを非常に長い間探してきました。 ;-)それは宣言と一緒に働く。 - BTW、同じファイルに両方の関数を入れても、sbclはまだ未定義の関数警告を出します。 –

+1

@lllファイルを最初にコンパイルするのではなく、読み込んでいるだけです。 replから、 '(load(compile-file" file.lisp "))'を使うか、Slime/Slyから 'C-c C-k'を使う。 – jkiiski

+0

実際に私は、標準の呼び出し 'コンパイル単位'がコンパイルのセマンティクスに影響していないと思います。後で同じファイルに定義される前に使用されているファイル内の関数のコンパイラの意味論は、 'コンパイル単位'とは関係がありません。コンパイル単位の概念ではなく、 ' - コンパイル単位では漠然としか定義されていません。 –

1

defunの順序を変更するだけです。まず、f2とfを定義します。

+0

コールグラフにサイクルを作成する相互再帰がある場合は、この方法を使用できません。 – Kaz

+0

私はこの点を明らかにするために感謝します。 –

+0

定義は、優れたプログラム構成です。しかし、大規模なプログラムでは長い時間をかけて維持するのは難しいが、関数を動かすことはなく、マージを妨げる醜いテキスト差分を作成する。多くの場合、「おかげで、ここからこの関数を呼び出す必要がありますが、後で定義します。 – Kaz

4

関数が同じファイル内にある場合、コンパイラは警告を出しません。

例SBCLは:

bash-3.2$ sbcl 
This is SBCL 1.3.10, an implementation of ANSI Common Lisp. 
More information about SBCL is available at <http://www.sbcl.org/>. 

SBCL is free software, provided as is, with absolutely no warranty. 
It is mostly in the public domain; some portions are provided under 
BSD-style licenses. See the CREDITS and COPYING files in the 
distribution for more information. 
* (compile-file "/tmp/order.lisp") 

; compiling file "/private/tmp/order.lisp" (written 28 NOV 2016 12:14:37 PM): 
; compiling (DEFUN F ...) 
; compiling (DEFUN F2 ...) 

; /tmp/order.fasl written 
; compilation finished in 0:00:00.178 
#P"/private/tmp/order.fasl" 
NIL 
NIL 
* (load *) 

T 
* 
3

あなたは彼らが同じコンパイル単位になるためにCommon Lispでは同じファイルに機能を配置する必要はありません。

これを行うことはアンチパターンです。大規模なプログラムはもちろんモジュールから構築され、その大部分は別のモジュールにある関数を呼び出します。これについての警告を避けるために、プログラム全体を単一の物理モジュールにロールアップすることはできません。

Lispはコンパイルのクラスタを単一のコンパイル単位と見なさされるメカニズムがあります。with-compilation-unitマクロを:

(with-compilation-unit 
    (compile-file "file-f") 
    (compile-file "file-f2")) 

あなたは航空自衛隊のビルドシステムを使用している場合、私はそれが下with-compilation-unitを行い思い出すように見えますあなたのためのフード、システムのすべてのファイルの周り。

この方法は、延期された警告を排除するのに役立ちます。つまり、実装で未定義の識別子が警告されても、がコンパイル単位の最後までを延期する場合、このマクロを使用すると、延期は複数のファイルにまたがる合計コンパイル単位の終わりまで拡張されます。

未定義の識別子に関する警告が延期されている場合、目的はそれらの警告を排除することです。以前に定義されていない関数の定義が変換単位の最後の前に現れる場合、警告を抑制することができます。このマクロを使用すると、あるファイルの定義で別のファイルの遅延警告を抑制することができます。

実装が警告を延期しない場合、マクロは助けになりません。

+0

これは、コンパイル単位の終わりまで警告を放棄します。問題は、警告を取り除くことでした。 –

+0

これについて少し考えても、WITH-COMPILATION-UNITを2つのファイルのコンパイルの周りにラッピングするだけで、警告を取り除くのは良い考えではないようです。この関数は最初のファイルではまだ定義されていません。 –

+0

@RainerJoswig私は、この警告を取り除いてくださいと言うANSI CLの方法を認識していません。アイデアは**実装が警告を防御している場合**は 'with-compilation-unit'が複数のファイルにわたってその延期を延長するということです。実装は、不必要なものを押しつぶす目的で警告を正確に延期します。機能の定義がコンパイル単位の終わりより前に見られると、遅延した "未定義関数"警告は自発的に消えます。 – Kaz

関連する問題