神奇的自产生程序
admin
2023-07-31 01:48:06
0

最近读到冯·诺依曼的《Theory of Self-Reproducing Automata》的中译本,被自复制自动机理论深深吸引了!

问题(自产生程序):编写一个程序,不读取任何输入,只把自己的源代码输出。

这个问题是个非常本质的问题,跟使用什么编程语言无关(不要想到使用反射之类的东西)。

试想,如果要输出自己的源代码,那么,显然,程序中应该有“print …”语句。但 print 什么出来呢?如果硬要写的话就会变成:

print \"print \\\\\"print ......\\\\\"\"

最后是一个无限循环。

一般地,我们知道,如果程序 A 能产生程序 B ,那么 A 必须包含 B 的全部信息,而且应该比 B 的信息还多,因为还要包含额外的打印语句。也就是说,一般情况下,信息是减少的。而这个自产生程序,自己要包含自己的全部信息,从某种程度上已经具有生命的意味了。

下面列出一些自产生程序及其思路。

首先需要注意的是,使用编程语言本身的反射功能或者读取文件等做法都被视为 cheating ,比如这样的 bash 脚本:

#!/bin/sh
cat $0

或者像这样的 javascript :

function a() { console.log(a.toString(), \"a()\"); } a()

因为这些程序没有体现出自产生程序的递归和自指特性,或者结果严重依赖于编程语言的具体实现。

不cheating的思路主要有以下几种:

输出源代码在该语言中的转义

Python :

s = \"\'s = \' + repr(s) + \'\\\\nprint(\' + s + \')\'\"
print(\'s = \' + repr(s) + \'\\nprint(\' + s + \')\')

Lua 5.1 :

s = \"string.format(\'s = %q\\\\nprint(%s)\', s, s)\"
print(string.format(\'s = %q\\nprint(%s)\', s, s))

另一个 Lua 版:

s = \"s = %q\\
print(string.format(s, s))\"
print(string.format(s, s))

Scala :

def e(s: String) = (\"\\\"\" + s.replace(\"\\\\\", \"\\\\\\\\\").replace(\"\\\"\", \"\\\\\\\"\") + \"\\\"\")
val s = \"\\\"\\\"\\\"def e(s: String) = (\\\"\\\\\\\"\\\" + s.replace(\\\"\\\\\\\\\\\", \\\"\\\\\\\\\\\\\\\\\\\").replace(\\\"\\\\\\\"\\\", \\\"\\\\\\\\\\\\\\\"\\\") + \\\"\\\\\\\"\\\")\\\"\\\"\\\" + \\\"\\\\nval s = \\\" + e(s) + \\\"\\\\nprintln(\\\" + s + \\\")\\\"\"
println(\"\"\"def e(s: String) = (\"\\\"\" + s.replace(\"\\\\\", \"\\\\\\\\\").replace(\"\\\"\", \"\\\\\\\"\") + \"\\\"\")\"\"\" + \"\\nval s = \" + e(s) + \"\\nprintln(\" + s + \")\")

用某种方法 encode 源代码,使之不包含引号,然后还原出源代码

Bash :

#!/bin/sh
s=\'\\x22#!/bin/sh\\ns=\\x27$s\\x27\\necho $(echo -e $s)\\x22\'
echo \"#!/bin/sh
s=\'$s\'
echo $(echo -e $s)\"

Lua 5.2 使用 load():

s = \"a,q,b=string.char(39),string.char(34),string.char(92) return a..\'s = \'..q..a..\'..s..\'..a..q..b..\'nprint(\'..a..\'..load(s)()..\'..a..\')\'..a\"
print(\'s = \"\'..s..\'\"\\nprint(\'..load(s)()..\')\')

Scala :

~~~~ {.hl}
val s = \"%22val+s+%3D+%5C%22%22+%2B+s+%2B+%22%5C%22%5Cnprintln%28%22+%2B+java.net.URLDecoder.decode%28s%2C+%22UTF-8%22%29+%2B+%22%29%22\"
println(\"val s = \\\"\" + s + \"\\\"\\nprintln(\" + java.net.URLDecoder.decode(s, \"UTF-8\") + \")\")
~~~~

使用 eval :在 eval 的字符串中引用自己
-------------------------------------

Lua load() 的另一种用法:

```lua
s = \"print(string.format(\'s = %q load(s)()\', s))\" load(s)()

js 的 eval()

s = \"q = String.fromCharCode(34); console.log(\'s = \' + q + s + q + \'; eval(s)\')\"; eval(s)

使用语言中的更强的转义机制

类似上面的第二种,但不用引号。

Lua 的 long string :

x = [[\"x = [\"..\"[\"..x..\"]\"..\"]\\nprint(\"..x..\")\"]]
print(\"x = [\"..\"[\"..x..\"]\"..\"]\\nprint(\"..x..\")\")

Scala 的三引号:

val s = \"\"\"\"val s = \\\"\\\"\\\"\" + s + \"\\\"\\\"\\\"\\nprintln(\" + s + \")\"\"\"\"
println(\"val s = \\\"\\\"\\\"\" + s + \"\\\"\\\"\\\"\\nprintln(\" + s + \")\")

使用 C 的宏

先执行传入的参数,再把参数变成字符串。

gcc :

#define p(a) int main(){a;puts(\"p(\"#a\")\");return 0;}
p(puts(\"#define p(a) int main(){a;puts(\\\"p(\\\"#a\\\")\\\");return 0;}\"))

至于它们是怎么实现的,就留给读者自己琢磨了。自产生程序也称为 Quine ,可以参考 Quine Page 。


via henix.info

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
项目管理和工程管理的区别 项目管理 项目管理,顾名思义就是专注于开发和完成项目的管理,以实现目标并满足成功标准和项目要求。 工...