問題タブ [homoiconicity]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
assembly - ホモイコニックで「制限のない」自己修正コード + Lisp は本当に自己修正ですか?
私の Lisp に関する知識はごくわずかであることを率直に認めます。しかし、私はその言語に非常に興味があり、近い将来、それを真剣に学び始める予定です. これらの問題に対する私の理解には間違いなく欠陥があるため、明らかに間違っていることを言う場合は、反対票を投じるのではなく、コメントして修正してください。
真のホモイコニックで自己修正可能な言語
Homoiconicity (コードはデータと同じ表現を持つ) と無制限の自己変更 (新しいコードを発行したり、関数ポインターを変更したりするだけでなく、実行中のコードのあらゆる側面を変更できることを意味する無制限の意味) の両方をサポートするプログラミング言語の例を探しています/代議員。)
私がこれまでに見つけた、この基準に適合する例は 3 つしかありません。
- マシンコード。すべてが数字であるホモイコニック。ポインターが含まれているという点で無制限に変更可能であり、そのアドレスがコードまたはデータを保持しているかどうかに関係なく、任意のメモリ アドレスを操作するために使用できます。
- マルボルジ。マシンコードと同じ理由。すべての命令は、実行後に自身を変更します
- DNA。プログラミング言語ではありませんが、それでも興味深いものです。マシンコードと同じ意味での自己変更ではありません。実際の命令とデータが変更された場所。ただし、それは自己複製であり、以前の状態に応じて変異/進化する可能性があります (放射線などの副作用が時々発生します)。とにかく、これは自己修正の間接的な方法です。簡単に言えば、DNA は自己改変することができますが、それは関連する突然変異と共にその全体を複製することによって行われます。DNA の物理的な文字列は「不変」です。
Lisp がこのリストにない理由
Lisp はそのリストに含まれていません。なぜなら、Lisp はほぼホモイコニックであり、制限付きの自己変更しかサポートしていないように思われるからです。次のようなことができます
と同じことを行います
最初のバージョンでは(+ 1 2 3)
は生のコードですが、2 番目のバージョンではデータです。このステートメントが真実であると仮定することにより、Lisp はホミニックでさえないと主張することができます。コードは、リスト/ツリー/S 式の両方であるという意味で、データと同じ表現をしています。しかし、これらのリスト/ツリー/S 式のどれがコードで、どれがデータであるかを明示的にマークしなければならないという事実は、結局のところ Lisp はホミニックではないと言っているように思えます。表現は非常に似ていますが、コードまたはデータを扱っているかどうかを実際に言わなければならない細部が異なります。これは決して悪いことではありません (実際、それ以外のことはすべて狂気です) が、Lisp とマシン コードの違いを浮き彫りにしています。マシン コードでは、どの数値が命令で、どの数値がポインターで、どの数値がデータであるかを明示的にマークする必要はありません。
これは、無制限の自己変更に対するさらに強力なケースです。もちろん、コードを表すリストを取得して操作することもできます。たとえば、
に
そして、あなたはそれを実行しますeval
。しかし、これを行うと、コードをコンパイルして実行するだけです。既存のコードを変更するのではなく、新しいコードを発行して実行するだけです。C# は式ツリーを使用してまったく同じことを行うことができますが、形式があまり便利ではありません (これは、独自の AST である Lisp とは対照的に、C# コードがその AST とは異なる表現を持つために発生します)。実際にソース ファイル全体を取得し、実行中にそのソース ファイル全体を変更して、ソース ファイルに加えられた変更がプログラムの動作にリアルタイムで影響を与えることはできますか?
これを行う何らかの方法がない限り、Lisp はホモニックでも自己修正でもありません。(定義に関する議論を先延ばしにするために、Lisp はホモイコニックでもなければ、マシン コードと同じ程度の自己修正でもありません。 )
Lisp Homoiconic/Unrestrictly 自己変更可能にする方法
Lisp をマシンコードのようにホモイコニック/自己修正可能にする 3 つの方法が考えられます。
- 非フォンノイマン アーキテクチャ。誰かが、プログラムの最下位レベルの表現が直接実行できる AST である驚くべき仮想マシンを発明できたら (それ以上のコンパイルは必要ありません)。そのようなマシンでは、AST は実行可能な命令とデータの両方を表します。残念ながら、AST は依然としてコードまたはデータのいずれかでなければならないため、問題は解決されていません。eval 関数が存在しても、これは変わりません。機械語では、コードとデータの間を好きなだけ行ったり来たりできます。一方、eval と Lisp では、リストをデータからコードに「評価」して実行すると、そのリストを再びデータとして取得する方法はありません。実際、そのリストは永久になくなり、その値に置き換えられました。たまたまポインターである重要なものが欠けている可能性があります。
- ラベルを一覧表示します。すべてのリストにも一意のラベルが必要である場合、特定のラベルを持つリストに対して関数を実行することにより、間接的な自己変更を行うことができます。継続と組み合わせることで、最終的にマシンコードと同じ意味で自己修正コードが可能になります。ラベルは、マシン コードのメモリ アドレスと同等です。例として、AST の最上位ノードに「main」というラベルが付いている Lisp プログラムを考えてみましょう。次に、main 内で、ラベル、整数、アトムを受け取る関数を実行し、アトムを、関数に指定されたインデックスに一致するラベルを使用してリストにコピーできます。次に、メインで現在の継続を呼び出します。ほら、自己修正コード。
- Lisp マクロ。私は Lisp マクロを理解するのに時間をかけたことがありません。実際、それらは私が考えていることを正確に実行する可能性があります。
ポイント 1. と 2. を組み合わせると、完全に自己変更的な Lisp が生成されます。説明されている魔法の Lisp マシンを作成できるという条件で。2. 単独で自己変更 Lisp を作成できますが、フォン ノイマン アーキテクチャでの実装は非常に非効率的です。
質問
- マシンコード、DNA、malbolge 以外に、完全自己改変が可能でホモイコニックな言語はありますか?
- (上記のテキストで tl;dr を実行した場合は、わざわざ回答しないでください) . Lispは本当にホモイコニック+自己修正ですか? もしあなたがそうおっしゃるなら、私の議論のどこで私が道に迷ったのかを正確に引用していただけますか?
付録
制限のない自己修正を伴うがホモニシティを持たない言語
- 組み立て。コードは数字ではなく単語を使用するため、同義性は失われますが、メモリに対する完全な制御を保持し、無制限の自己変更を可能にするポインタがまだあります。
- 生のポインターを使用するすべての言語。例: C/C++/Objective C。アセンブリと同じ引数
- 仮想ポインターを含む JIT 言語。たとえば、安全でないコンテキストで実行されている C#/.net などです。Assembly と同じ引数。
何らかの形で関連/興味深い可能性のあるその他の概念と言語: Lisp、Ruby、Snobol、Forth とコンパイル時のメタプログラミング、Smalltalk とそのリフレクション、すべてが関数であるというプロパティを持つ型指定されていないラムダ計算 (これは、ラムダ計算を直接実行するマシンを発明できれば、ラムダ計算はホモイコニックであり、フォン ノイマンのマシン コードは、そのマシンで実行するとそうではありません.[そして、ゲーデルの定理は実行可能になるでしょう.ハハ、恐ろしい考え :P])
lisp - 同性愛のレベル
これは私の前の質問へのフォローアップです。私は、Lisp コードがフォン ノイマン アーキテクチャ上のマシン コードと同じくらいホモイコニックであるとは確信していません。どちらの場合もコードがデータとして表現されることは明らかですが、Lisp よりも機械語でこのプロパティをはるかに自由に利用できることも明らかです。
マシン コードをいじくり回すと、コードの自己変更が非常に簡単になり、多くの場合偶然に (私の経験では) 面白い結果が得られます。単純な「0 ~ 15 の数字を出力する」プログラムを作成しているときに、ポインターの 1 つに「off by one」エラーが発生することがあります。レジスタ 1 にあるものを、次の命令を含むメモリ内のアドレスに誤ってダンプしてしまい、代わりにランダムな命令が実行されます。(ある種の「goto」の場合は常に素晴らしいです。神はそれがどこに行き着くのか、その後何をするのかを知っています)
コードとデータの間に分離はありません。すべてが同時に命令 (単なる NOP であっても) であり、ポインタであり、昔ながらの数値でもあります。また、目の前でコードが変更される可能性があります。
私が頭を悩ませてきた Lisp のシナリオを教えてください。次のプログラムがあるとします。
ここで、私がやりたいことは、このプログラムに、* を + に変更し、<= を >= に変更し、そこのどこかに (+ 1 2 3) を貼り付けて、一般的に関数を盗聴する Lisp コードを追加することです。上。そして、結果として生じる絶対的な混乱をプログラムに実行させたいのです。
重要なポイント: サンプル コードに致命的なエラーがない限り、変更できるのはその-– More code goes here –-
部分だけです。上に表示されているのはコードです。リスト全体を引用して変数に格納して、操作して同じ名前の別の関数として吐き出すことができるようにしたくありません。factorial をまったく別のものとして標準的に再定義したくありません。マシンコードのように、画面に表示されているコードが目の前で変化するようにしたいのです。
これが不可能/不合理な要求である場合、ホモイコニシティは言語が持っている、または持っていない個別の特性ではなく、スペクトルであり、Lisp は最先端ではないという考えが私の心の中でさらに固まるだけです。(あるいは、Lisp はホモイコニックであり、マシンコード風の自己変更を説明する他の用語を探しています)
emacs - Lispでコードをデータとして扱うと便利なのはなぜですか
私は今 emacs lisp を学んでいますが、なぜコードをデータとして扱うことが有用なのか疑問に思っています。このアプローチの利点は何でしょう。これは、データとコードの間に明確な分離が存在する従来のフォンノイマンアーキテクチャの代替であるため、1つの説明を見ました。この決定の意味を理解したいのですが、アイデアを得てください。
前もってありがとう、ニック。
lisp - Elixir や Julia のような言語はどのような意味でホモイコニックなのですか?
Lisp のホモイコニシティは簡単に確認できます。
(+ 1 2)
+
は、 with1
を引数として呼び出す関数であると同時に、 、、および2
を含むリストでもあります。それは同時にコードとデータの両方です。+
1
2
ただし、Julia のような言語では次のようになります。
1 + 2
Expr
これをJulia で解析できることはわかっています。
:(1 + 2)
そして、AST を取得して操作できます。
julia> Meta.show_sexpr(:(1+2))
(:call, :+, 1, 2)
したがって、Julia (および Elixir) でプログラムの AST を操作できます。しかし、それらは Lisp と同じ意味でホモイコニックなのでしょうか?コードのスニペットは本当に言語自体の単なるデータ構造なのでしょうか?
1 + 2
Juliaのようなコードがすぐにデータであることがわかりません。Lisp のようなコード(+ 1 2)
は単なるリストです。では、それはまだホミコニックですか?