Lisp をコンパイルして動的にする方法がわかりません。言語がコードを操作、変更、生成できるようにするためには、解釈される必要があるのではないでしょうか? 言語が完全にコンパイルされていても動的であることは可能ですか? または、何か不足していますか?Lisp は、コンパイルと動的の両方を可能にするために何をしているのでしょうか?
3 に答える
Lispは言語と実装の幅広いファミリーです。
Lispのコンテキストで動的とは、コードが実行時に一定の柔軟性を持っていることを意味します。たとえば、変更または交換できます。これは、動的に型付けされたものと同じではありません。
Lispでのコンパイル
多くの場合、Lisp実装には実行時に利用可能なコンパイラがあります。このコンパイラがインクリメンタルの場合、プログラム全体を必要としませんが、単一のLispフォームをコンパイルできます。次に、コンパイラがインクリメンタルコンパイルをサポートしていると言います。
ほとんどのLispコンパイラはJustInTimeコンパイラではないことに注意してください。プログラマーは、たとえばCommonLispで関数COMPILE
とを使用してコンパイラーを呼び出すことができCOMPILE-FILE
ます。次に、Lispコードがコンパイルされます。
さらに、コンパイラとインタプリタの両方を備えたほとんどのLispシステムでは、解釈されたコードとコンパイルされたコードの実行を自由に組み合わせることができます。
Common Lispでは、コンパイルされたコードがどれほど動的であるかをコンパイラーに指示することもできます。SBCL (または他の多くのコンパイラ)のコンパイラのようなより高度なLispコンパイラは、異なるコードを生成できます。
例
(defun foo (a)
(bar a 3))
上記foo
の関数は関数を呼び出しますbar
。
グローバル関数がbar
あり、それを再定義する場合、通常、Lispでは新しい関数bar
がによって呼び出されると予想されfoo
ます。再コンパイルする必要はありませんfoo
。
GNUCLISPを見てみましょう。仮想マシンのバイトコードにコンパイルされます。これはネイティブのマシンコードではありませんが、ここでの目的のために読みやすくなっています。
CL-USER 1 > (defun foo (a)
(bar a 3))
FOO
CL-USER 2 > (compile 'foo)
FOO
NIL
NIL
[3]> (disassemble #'foo)
Disassembly of function FOO
(CONST 0) = 3
(CONST 1) = BAR
1 required argument
0 optional arguments
No rest parameter
No keyword parameters
4 byte-code instructions:
0 (LOAD&PUSH 1)
1 (CONST&PUSH 0) ; 3
2 (CALL2 1) ; BAR
4 (SKIP&RET 2)
ランタイムルックアップ
BAR
したがって、への呼び出しが実行時ルックアップを実行することがわかります。シンボル を調べてからBAR
、シンボルの関数を呼び出します。したがって、シンボルテーブルはグローバル関数のレジストリとして機能します。
このランタイムルックアップをインクリメンタルコンパイラと組み合わせて(ランタイムで利用可能)、Lispコードを生成してコンパイルし、現在のLispシステムにロードして、Lispプログラムを少しずつ変更することができます。
これは、間接参照を使用して行われます。実行時に、Lispシステムは。という名前の現在の関数を検索しますbar
。ただし、これはコンパイルや解釈とは関係がないことに注意してください。コンパイラがコンパイルfoo
され、生成されたコードがこのメカニズムを使用する場合、それは動的です。したがって、インタプリタされたコードとコンパイルされたコードの両方でルックアップのオーバーヘッドが発生します。
70年代以降、Lispコミュニティは、コンパイラとインタプリタのセマンティクスを可能な限り類似させることに多大な努力を払ってきました。
Common Lispのような言語を使用すると、コンパイラーはコンパイルされたコードの動的性を低下させることもできます。たとえば、実行時にコードの特定の部分の関数を検索しないことによって。
言語がコードを操作、変更、生成できるようにするためには、解釈される必要があるのではないでしょうか?
いいえ。
言語が完全にコンパイルされていても動的であることは可能ですか?
はい。
または、何か不足していますか?
はい。
Lisp は、コンパイルと動的の両方を可能にするために何をしているのでしょうか?
Java や PyPy のほとんどの実装と同様に、オンザフライでコンパイルされます。
遅延バインディングであるため、コンパイルと動的化を同時に行うことができます。関数と引数のリストを実行し、それに何かを追加してから再度実行できます。基本的に、関数全体だけでなく、コードの各部分を実行できます。