Lisp用のネイティブコードコンパイラはありますか?動的な性質、ガベージコレクション、マクロなど、どの程度までコンパイルできますか?
多くのLISPコンパイラは「ネイティブ」コードにコンパイルされます。 「ネイティブ」とは、ここでは「マシンコード」(32ビットまたは64ビットモードのx86、PowerPC、SPARCなど)を意味します。
その他の質問:
「非ネイティブコード」コンパイラは単一ファイルの実行可能ファイルを生成できますか? ->はい。
「ネイティブコード」コンパイラは単一ファイルの実行可能ファイルを生成できますか? ->はい。
「ネイティブ」は「ネイティブ」ですか? -> LISPシステムには、ほとんどの場合、独自の内部データ構造レイアウト(CLOSクラス)、独自のエラー処理(「条件」)、独自のメモリ管理(ガベージコレクション)、独自のライブラリなどがあります。
lISPはGCなしで実行できますか? ->通常はありません。例外があります。
アプリケーションのサイズはどうですか? ->デフォルトでは、LISPアプリケーションを生成する簡単な方法は、多くの場合、大きな実行可能ファイルにつながります。実行可能ファイルには、ライブラリ、すべてのシンボルの名前、関数への引数リストに関する情報、コンパイラ、デバッガ、ソースコードの場所情報などを含むLISP全体が含まれます。一部のコンパイラは、大きなコードも生成します(SBCLはその一例です)。
アプリケーションのサイズを縮小する方法はありますか? ->それはLISPシステムに依存します。 LispWorksやAllegroCLのような商用LISPシステムはそうすることができます。アプリケーション配信の場合、未使用のコードの削除、デバッグ情報の削除、LISPの一部(ライブラリ、コンパイラなど)の削除などを行うことができます。
commonLISPシステムは小さな実行可能ファイルを生成できますか?私は本当に小さいという意味です。 ->そうではありません。実行可能ファイルは、ラージ(CCL)または非常にラージ(SBCL)のいずれかです。一部のCommonLISPシステムは、中規模の実行可能ファイルを生成できます。しかし、実際に小さな実行可能ファイルを生成できるものはありません。
本当に小さな実行可能ファイルを生成する方法は本当にありませんか? ->数年前、大きなライブラリなしで比較的コンパクトなCコードを生成するコンパイラが作成されました。しかし、これらのコンパイラは保守されていません。
実行可能ファイルを縮小する他の方法はありますか? ->複数のLISPアプリケーションを実行する場合は、ランタイム、コンパイラ、ライブラリを1つ以上の共有ライブラリで再利用するのが理にかなっています。そうすれば、ランタイムが共有ライブラリ(または同様のもの)としてすでにインストールされている場合、配信するコードは小さくなります。
使用しているLISPがアプリケーション配信としてサポートしているものを見つけるにはどうすればよいですか? ->マニュアルを読み、他のユーザーに聞いてください。
さて、ほとんどのCommonLISPシステムは小さなアプリケーションを生成できません。より小さな実行可能ファイルを生成できる他のLISP方言はありますか? ->はい、一部のSchemeコンパイラは可能です。
common LISPはランタイムエラーをどのように処理しますか? ->アプリケーションの生成方法によって異なります。デフォルトでは、LISPデバッガーを取得します(削除していない限り)。ただし、アプリケーションで独自のエラー処理ルーチンを使用して、デバッガーが表示されないようにすることができます。
本当に小さな実行可能ファイルを生成することが1つではない場合、Common LISPの特定の強みは何ですか? -> REPLをインクルードしてアプリケーションと対話し、インクルードされたコンパイラーを使用して実行時に新しい(または変更されたコード)をコンパイルし、FASL(コンパイルされたLISPコード)ローダーを使用できます実行時に追加のネイティブコードをロードするために(プラグイン、パッチ、拡張機能などを考えてください)、エラー回復を含む高度なエラー処理が可能です...
しかし、LISPは動的ですか? ->はい、動的とは、実行時に多くのことを変更できることを意味します。たとえば、Common LISPでは、実行時にCLOSクラスを変更でき、クラスのインスタンスが変更に採用されます。しかし、さまざまなLISPシステムには、動的機能の一部を削除するさまざまな方法があります。構造はCLOSクラスよりも動的ではありません。タイプを宣言し、さまざまな最適化設定(速度、安全性、デバッグなど)でコンパイルできます。関数をインライン化できます。もっと。
関数のコンパイル済みコードを確認する簡単な方法は、CommonLISP関数DISASSEMBLEを使用することです。 x86-64MacでのClozureCLの例
? (defun foo (x y) (if (= x y) (sin x) (* y (cos x))))
FOO
? (disassemble 'foo)
L0
[0] (leaq (@ (:^ L0) (% rip)) (% fn))
[7] (cmpl ($ 16) (% nargs))
[10] (jne L209)
[16] (pushq (% rbp))
[17] (movq (% rsp) (% rbp))
.。
[172] (pushq (@ 77752))
[179] (jmpq (@ 10 (% temp0)))
L189
[189] (leaq (@ (:^ L0) (% rip)) (% fn))
[196] (jmpq (@ .SPNVALRET))
L209
[209] (uuo-error-wrong-number-of-args)
NIL
DISASSEMBLEの出力は、明らかにプロセッサアーキテクチャ、OS、使用されているLISPコンパイラ、および現在の最適化設定に依存します。
ネイティブコードにコンパイルする多くのLISPコンパイラがあります。 CMUCL、SBCL、ClozureCLは、オープンソースのLISPコンパイラで知られています。
ガベージコレクションは、ネイティブコードへのコンパイルの障害にはなりません。また、場合によっては、LISPはGCを必要としないスタック割り当てを使用でき、パフォーマンスを大幅に向上させることができます(動的エクステント宣言を使用。少なくともSBCLはこれをサポートします)。
マクロ(および読み取り時(読み取りマクロと読み取り評価)、コンパイル時(マクロ、コンパイラマクロ、eval-whenのコード)で実行されるコード)には、増分コンパイルが必要です(最初のマクロ関数をコンパイルする必要があります。その後、マクロを使用するコードをコンパイルできます)。これはコンパイルをやや複雑にしますが、それほど問題ではありません。また、マクロとコンパイラマクロは、プログラマがコードジェネレータとコードオプティマイザを記述して、本質的にコンパイラをカスタマイズできるため、コンパイルプロセスにも役立ちます。
したがって、コンパイラはいくつかの単純な言語(Cなど)よりも複雑ですが、複雑さは管理可能です( CMU Common LISPの設計 を参照)。
Common LISPの動的な性質は制御可能であり、効率的にコンパイルできるように設計されています。他のいくつかの動的言語(Pythonなど)とは対照的に、ダイナミズムは制限されており(実行時に現在の字句環境を取得できないなど)、コンパイラーに最適化の自由を与えます。
ネイティブコードには膨大な数のLISPコンパイラがあります。 http://www.thefreecountry.com/compilers/commonlisp.shtml を参照してください。 CMU CommonLISPコンパイラ。
あなたは賭けます。 Chez Scheme (商用コンパイラ)は優れたコンパイラの1つです。 GambitとLarcenyは、ネイティブコードも生成するリサーチコンパイラです。
Chicken Schemeを忘れないでください。
はい。 http://en.wikipedia.org/wiki/Common_LISP を参照してください。 Steel Bank Common LISP (かなり人気のある実装)がデフォルトですべてをネイティブにコンパイルすることに言及しています。ガベージコレクションなどが使用されているという事実は、ネイティブコードの障害にはなりません。これは、何らかのランタイムが必要であることを意味します。しかし、それで何? Cにもランタイムがあります。