定義上、同像性という言葉は次のことを意味します。
コードとデータの同じ表現
LISPでは、これは引用符で囲まれたリストを作成して評価できることを意味します。(car list)
関数と(cdr list)
引数も同様です。これは、コンパイル時または実行時に発生する可能性がありますが、インタープリターが必要です。
コンパイル時インタプリタなしでコンパイルされた言語も同像性である可能性はありますか?それとも、同像性の概念は通訳者に限定されていますか?
定義上、同像性という言葉は次のことを意味します。
コードとデータの同じ表現
LISPでは、これは引用符で囲まれたリストを作成して評価できることを意味します。(car list)
関数と(cdr list)
引数も同様です。これは、コンパイル時または実行時に発生する可能性がありますが、インタープリターが必要です。
コンパイル時インタプリタなしでコンパイルされた言語も同像性である可能性はありますか?それとも、同像性の概念は通訳者に限定されていますか?
「ホモイコニック」は一種のあいまいな構造です。「コードはデータです」は少し明確です。
とにかく、ウィキペディアのホモイコニックの最初の文はそれほど悪くありません。言語には、データ構造を使用したソース表現が必要であると書かれています. ソース表現としての「文字列」を忘れた場合 (それは些細なことであり、「ホモイコニック」という有用な概念を持つことはあまり役に立ちません)、Lisp にはソース コードを表すために使用されるリスト、シンボル、数字、文字列などがあります。EVAL 関数のインターフェースは、言語が処理しているソース表現の種類を決定します。この場合、Lisp、それは文字列ではありません。EVAL は、通常のさまざまなデータ構造を想定しており、Lisp の評価規則は、文字列がそれ自体に評価されることを決定します (したがって、プログラム式ではなく、単なる文字列データとして解釈されます)。数値はそれ自体にも評価されます。リスト (sin 3.0) は、記号と数字のリストです。評価規則によると、関数を表す記号を最初のオブジェクトとして持つこのリストは、関数適用として評価されます。データ、特殊演算子、マクロ アプリケーション、および関数アプリケーションには、このような評価ルールがいくつかあります。それでおしまい。
明確にするために: Lisp では、関数 EVAL は Lisp データ構造に対して定義されます。データ構造を期待し、その評価ルールに従って評価し、結果を返します - 再びそのデータ構造を使用します。
これは、ホモイコニックの定義と一致します。ソース コードには、Lisp のデータ型を使用したネイティブな表現があります。
さて、興味深い部分はこれです: EVAL がどのように実装されているかは問題ではありません。重要なのは、Lisp データ構造を使用してソース コードを受け入れ、コードを実行し、結果を返すことだけです。
したがって、EVAL がコンパイラを使用することは完全に合法です。
(EVAL code) = (run (compile-expression code))
いくつかの Lisp システムはこのように動作しますが、インタープリターを持っていないものもあります。
したがって、「Homoiconic」は、SOURCE コードにデータ表現があることを示しています。実行時にこのソース コードを解釈する必要がある、または実行がこのソース コードに基づいているとは言いません。
コードがコンパイルされている場合、実行時にコンパイラもインタープリタも必要ありません。これらは、プログラムが実行時にコードを評価またはコンパイルしたい場合にのみ必要になります。これは、多くの場合、必要ありません。
Lisp は、データの外部表現 (S 式) をデータの内部表現 (Lisp データ) に変換するプリミティブ関数READも提供します。したがって、ソースコードの外部表現をソースコードの内部表現に変換するためにも使用できます。Lisp はソース コードに特別なパーサーを使用しません。コードはデータであるため、READ しかありません。
はい。Lisp はネイティブ バイナリにコンパイルできます
私には奇妙な質問のようです:
まず、ホモイコニック部分は、プログラマーに提供されるインターフェースです。言語のポイントは、(手段は異なりますが) 上位レベルのプレゼンテーションと同じセマンティクスを保持する下位レベルの機能を抽象化することです。
dsm のマシン コード ポイントは良い点ですが、以下を提供します。
ここで下位レベルの実装が重要なのはなぜですか?
また:
コンパイル時インタープリターなしでコンパイルされた言語
それを解釈するプログラムがなければ、CPU にネイティブである必要があるため、CPU のネイティブ言語はホモイコニック (またはコードを実行する VM) である必要があります。
コンパイル時の解釈のない言語は...かなり制約されます...それらはまったくコンパイルされないためです。
しかし、私は専門家ではないので、要点を見落としているかもしれません。
最も文字通りの形式では、C はホモイコニックです。を使用して関数の表現にアクセスし、 を使用し&functionName
てデータを実行できますsomePtrCastToFnPtr(SomeArgs)
。ただし、これはマシン コード レベルであり、ある種のライブラリ サポートがないと、作業が非常に難しくなります。ある種の組み込み可能なコンパイラ (LLVM がこれを実行できることを覚えているようです) を使用すると、より実用的になります。
マシンコード自体はホモイコニックなので、そうです。
データまたは命令は、セマンティクス (およびおそらくそれらが存在するメモリのセグメント) の問題です。
Lisp は通常コンパイルされます。インタープリターの代わりに JIT コンパイラーを使用した実装がありました。
したがって、code-is-data 言語のインタープリター (「コンパイラーではない」という意味で) は必要ありません。
コンパイルは最適化された解釈です。インタープリターは、コードを表すデータの一部を受け取り、そのコードを「実行」します。コードの意味は、インタープリターの内臓を通る実行経路とデータフローに変わります。コンパイラは同じデータを受け取り、それを別の形式に変換してから、別のインタープリター (シリコン (CPU) に実装されたもの (CPU) またはおそらく偽物 (仮想マシン) に実装されたもの) に渡します。
これが、一部の Lisp 実装がインタプリタを持てない理由です。EVAL 関数は、コードをコンパイルして分岐できます。EVAL と COMPILE は、異なる操作モードを持つ必要はありません。(Clozure、Corman Lisp、SBCL は「コンパイラのみ」の Lisp の例です。)
コードの実行がコンパイルによって最適化されるかどうかではなく、最初のデータ部分が言語のホモイコニックの鍵となります。「コードはデータ」とは、「実行コードがデータ」ではなく、「ソースコードがデータ」という意味です。(もちろん、実行可能なコードはデータですが、データとは、操作したいコードの圧倒的に好ましい表現を意味します。)
はい; コンパイラのコピーを言語ランタイムに貼り付けるだけです。 Chez Schemeは、まさにそれを行う多くの優れたコンパイラの 1 つです。
問題は、多くのプロセッサが命令領域とデータ領域を分離し、プログラムが独自のコードを変更するのを積極的に妨げていることです。この種のコードはかつて「縮退コード」と呼ばれ、非常に悪いことと見なされていました。
インタープリター (および VM) には、プログラム全体をデータとして扱うことができ、唯一の「コード」がインタープリターであるため、その問題はありません。
VM の上に構築された言語 (.net clr、jre ect) は、オンザフライ コード生成を可能にする高度な技術を使用できます。その一つがIL織りです。ただし、ECMAScript/Lisp/Scheme ect の eval ほど明確ではありませんが、そのような動作をある程度エミュレートできます。
例については、Castle DynamicProxy を確認してください。よりインタラクティブな例については、LinqPAD、F# Interactive、Scala interactive を確認してください。