定义

自产生程序(英语: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))

运行效果如图

AutoHotkey Quine

另一个思路

在知乎上看到了一个 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))")

Another Quine

Footnotes

  1. https://rosettacode.org/wiki/Quine#AutoHotkey

  2. https://www.zhihu.com/question/38145793/answer/984510905