定义
自产生程序(英语:Quine),指的是输出结果为程序自身源码的程序。其英文名称以美国哲学家奎恩(Willard Van Orman Quine)命名,能够直接读取自己源码、读入用户输入或空白的程序一般都不视为自产生程序。
AutoHotkey 的 Quine
在 Rosetta Code 的 Quine 页面,列出了很多语言写的“自产生程序”。其中就有我使用的 AutoHotkey1:
FileRead, quine, %A_ScriptFullPath%
MsgBox % quine
然而这段代码是“作弊”的,因为 Quine 不允许查看自身代码也就不能使用 FileRead
。
我尝试着用 AHK v2 写出了真正的 Quine:
s:="s:={:c}{}{1:c},MsgBox(Format(s,34,s))",MsgBox(Format(s,34,s))
运行效果如图
另一个思路
在知乎上看到了一个 Quine 的构造方法2,算是比较通用的方式,有一点编译器自举的既视感,尝试用 AutoHotkey 实现了一遍。
首先这个方法语言支持匿名函数,这在 AutoHotkey 里叫做“胖箭头函数”。用其构造一个函数,可以连续打印两遍输入,第一遍使用括号将其包含,第二遍使用括号和引号将其包含。
quine := (s) => MsgBox(Chr(40) s Chr(41) Chr(40) Chr(34) s Chr(34) Chr(41))
quine("q") ; 打印 (q)("q")
quine("quine") ; 打印 (quine)("quine")
(quine)("quine") ; 打印 (quine)("quine")
这种 (q)("q")
的形式就表达了“声明一个函数对象,并把声明的字符串传入自身调用”。因此,我们接下来把第一行整句作为字符串传入 quine
函数来调用:
; 打印 (quine := (s) => MsgBox(Chr(40) s Chr(41) Chr(40) Chr(34) s Chr(34) Chr(41)))("quine := (s) => MsgBox(Chr(40) s Chr(41) Chr(40) Chr(34) s Chr(34) Chr(41))")
(quine)("quine := (s) => MsgBox(Chr(40) s Chr(41) Chr(40) Chr(34) s Chr(34) Chr(41))")
打印的结果就是一个自产生程序,最后,由于函数对象声明后立即调用,可以省去变量赋值而直接使用其匿名形式:
((s) => MsgBox(Chr(40) s Chr(41) Chr(40) Chr(34) s Chr(34) Chr(41)))("(s) => MsgBox(Chr(40) s Chr(41) Chr(40) Chr(34) s Chr(34) Chr(41))")