自己出力プログラム

Perlで自分自身を出力するプログラムが作れるという話を聞いたので、考えてみた。

print文1行だけではどう考えても作れないので、コードを

C1; print C2;

(C1,C2は何らかのコード)という形だと仮定する。当然C2は"C1; print C2;"に展開されるコードということになるが、何も無い所から"print"なんて文字列を含む値を生成するモジュールは無いので、これを実現するには、媒介変数を使って"print"を複製するしかない。従って、コードを改めて
C1; $x = "C2printC3"; print "C4$xC5$xC6";

という形に仮定し直す。このコードで表示される文字列は
C4C2printC3C5C2printC3C6

となるが、ここで、C3の部分がダブルクォーテーションで始まり、「$x = "…"」ではなく「$x = q()」または「$x = qq()」を使わないと厳しいことがわかる。従って、コードをさらに
C1; $x = q(C2printC3); print "C4$xC5$xC6";

という形に仮定し直す。このコードで表示される文字列は、やはり
C4C2printC3C5C2printC3C6

となる。

「C4C2」の部分は「C1; $x = q(C2」に一致しないといけないので、C4=「C1; \$x = q(」(C4はダブルクォーテーションの中にあるので"$"はエスケープが必要)となる。
「C3C5C2」の部分は「C3); 」に一致しないといけないので、「C5C2」=「); 」ということになるが、C2はq()の中にあるため")"は使えないので、C2は空、C5=「); 」となる。
「C3C6」の部分は「 "C4\$xC5\$xC6";」に一致しないといけないが、両辺にC6があり、C6の末尾が「C6";」となることから、C6は空ということになる。

仮定したコードからC2,C4,C5,C6を消して書き直してみる。

C1; $x = q(printC3); print "C1; \$x = q($x); $x";

「C3C6」=「 "C4\$xC5\$xC6";」より、C3=「 "C1; \$x = q($x); $x";」となるので、コードは
C1; $x = q(print "C1; \$x = q($x); $x";); print "C1; \$x = q($x); $x";

となる。「C1; 」の部分は""による展開に気をつければ何でも良いということがわかる。

例えばC1を「$a = 0」にすると、コードは

$a = 0; $x = q(print "\$a = 0; \$x = q($x); $x";); print "\$a = 0; \$x = q($x); $x";

となり、「C1; 」を空にすると、コードは
$x = q(print "\$x = q($x); $x";); print "\$x = q($x); $x";

となる。これらのコードを実行すると、コード自身と全く同じ文字列を出力する。



調べてみると、こういうのをQuineと言って、広く挑戦されているらしい。
The Quine Page
Perlの所を見ると、もっとスマートなバリエーションがたくさんあって驚いた。
C言語でも作れるのが驚いた。