Prompt
自分自身のソースコードを引数にする、再帰的なevalをするとどうなる?
それはまさに、情報工学における 「自己言及の迷宮」 への招待状だね!
自分自身のソースコードを読み込んで eval し、さらにその中で自分を eval する……。この試みは、単なる「無限ループ」を超えて、いくつかの非常に興味深い(そして破壊的な)現象を引き起こすよ。
君が追求する「一意な定義」が、自分自身を飲み込んで崩壊していく様子を解剖してみよう。
1. 物理的な結末:スタックオーバーフローとリソース枯渇
最も現実的で退屈な結末は、OSやランタイムによる強制終了だ。
-
スタックの積み上がり:
evalを呼び出すたびに、現在の実行コンテキスト(変数やリターンアドレス)がメモリ(スタック領域)に積まれていく。 -
メモリの爆発: ソースコードを文字列として読み込む処理が再帰的に走るため、ヒープメモリも猛烈な勢いで消費される。
-
結果: 現代の賢いランタイム(Node.jsやPython)なら、
Maximum call stack size exceededというエラーを吐いて、スイスチーズの穴が一直線になる前にシステムを保護してくれるよ。
2. 理論的な面白さ:クワイン(Quine)との境界線
自分自身のソースコードを扱うプログラムといえば、「クワイン(Quine)」 が有名だね。「自身のソースコードと完全に同じ文字列を出力する」というパズルだ。
-
君の試み: クワインは「出力」で終わるけれど、君の案は「実行(eval)」を繰り返す。
-
メタ循環評価器: もしその
evalが「自分自身のコードを解釈するインタプリタ」そのものだった場合、それは 「メタ循環評価器(Meta-Circular Evaluator)」 と呼ばれる、Lispの世界では聖典のような概念になるんだ。 -
無限の鏡: 鏡の中に鏡を置くように、実行レイヤーが「実行している自分」をさらに「実行」し続ける。
3. 「evalの解釈」による挙動の変化
その「自分自身のソースコード」が、どうやって eval を呼び出しているかによって、崩壊の仕方が変わるよ。
パターンA:単純な無限再帰
JavaScript
// self.js
const fs = require('fs');
const code = fs.readFileSync(__filename, 'utf8');
eval(code); // ここで自分をもう一度実行
この場合、1行目の require から順番に実行され、3行目でまた1行目に戻る。これは純粋な 「無限ループ」 だ。
パターンB:文字列の増殖(ラザニアの肥大化)
もしソースコードが「自分を文字列として加工してから eval する」ようなものだったら?
- 実行するたびに文字列が で増えていき、メモリがあっという間にパンクする。
4. セキュリティ上の「自己崩壊」
「属人性の排除」を目指す君にとって、これは最悪の悪夢だ。
-
汚染の深化: もし最初の
evalに渡すソースコードに、ほんの少しの「悪意(あるいはバグ)」が混じっていたら? -
そのバグは再帰のたびに増幅され、修正不可能なレベルでメモリ空間を汚染していく。
-
一意性の喪失: 再帰の深さ(レイヤー)によって変数の状態が変わってしまうと、どのレイヤーの自分が「本当の自分」なのか、論理的に定義できなくなってしまうんだ。
見落とされがちな視点:コンパイル言語での「自己再帰」
もしこれを Rust でやろうとしたらどうなるか?
Rust には実行時の eval がないから、代わりに 「自分自身のソースをコンパイルして実行するバイナリ」 を作ることになる。
-
main.rsが自分のソースを読み込む。 -
Command::new("rustc")で自分をコンパイルしてtemp_binを作る。 -
temp_binを実行する。 -
その
temp_binがまた自分をコンパイルして……。
これは 「コンパイラ爆弾」 の一種になり、ディスク容量とCPUを食い尽くす、物理的な災害をもたらすよ。
結論
自分自身を eval する行為は、「定義(コード)」と「実体(実行)」の境界線を消し去る行為 だ。
それは数学的には美しいけれど、現実のシステムにおいては 「自己言及的な矛盾」 を引き起こし、最終的には計算機資源という物理限界にぶつかって幕を閉じる。
君のデジタルガーデン(https://garden.asappy.xyz)のリンクを、そのページ自体の中に無限に埋め込んでいくような、そんな眩暈のするような試みだね。
次は、「こうした自己言及の論理(ゲーデルの不完全性定理など)が、どうやって現代の計算機理論の基礎になっているのか」 という、もっと深い哲学的な話をしてみる?
Would you like me to code a safe (depth-limited) example of a self-evaluating script in JavaScript to show exactly how the stack grows?