更改
→建构性的自指
我们不妨把这段程序的5个部分进行归并,写成由下面的三部分构成的:<math> (Copy_o \ Popup_o \ Control)</math>,其中Copy就是5部分中的第二部分,即相当于一个拷贝字符串的程序,你输入
我们不妨把这段程序的5个部分进行归并,写成由下面的三部分构成的:<math> (Copy_o \ Popup_o \ Control)</math>,其中Copy就是5部分中的第二部分,即相当于一个拷贝字符串的程序,你输入
给Copy什么字符串,Copy就会把那个字符串再原封不动地吐出来;Popup这部分就是原来的5部分中的第四部分,即函数<math>p</math>,它的作用相当于一个弹出操作,也就是为输入的字符
给Copy什么字符串,Copy就会把那个字符串再原封不动地吐出来;Popup这部分就是原来的5部分中的第四部分,即函数<math>p</math>,它的作用相当于一个弹出操作,也就是为输入的字符
串脱去一层引号。如果输入的字符串原来是在第<math>n</math>层虚拟世界,则Popup的作用就是让字符串跳到第<math>n-1</math>层;最后Control这部分就相当于原来的第1、3、5这三部分以及最一开始的语句Print的总合,它的作用就相当于是为Copy和Popup制造出来的字符添加适当的连接词,使得最后的字符串能够拼接成与原来的程序一模一样的源程序,并将其打印到屏幕上。所以这句“Print(‘S(x){\nq=\’’+q+’\’;\nPrint(\’’+p(q)+’\’);\n}’);”就可以改写成(CopyоPopupоControl)(q)。其中“о”表示将不同的程序连接为一体。
串脱去一层引号。如果输入的字符串原来是在第<math>n</math>层虚拟世界,则Popup的作用就是让字符串跳到第<math>n-1</math>层;最后Control这部分就相当于原来的第1、3、5这三部分以及最一开始的语句Print的总合,它的作用就相当于是为Copy和Popup制造出来的字符添加适当的连接词,使得最后的字符串能够拼接成与原来的程序一模一样的源程序,并将其打印到屏幕上。所以这句<code>“Print(‘S(x){\nq=\’’+q+’\’;\nPrint(\’’+p(q)+’\’);\n}’);”</code>就可以改写成<math> (Copy_o \ Popup_o \ Control)(q)</math>。其中“о”表示将不同的程序连接为一体。
如果我们把一个计算机程序<math>X</math>的描述(或者称源代码)写为<math>\lambda(X)</math>,则自打印程序的第一条赋值语句就相当于给<math>q</math>赋予了<math>\lambda (Copy_o \ Popup_o \ Control)</math>,即<math> (Copy_o \ Popup_o \ Control)</math>这三个程序连在一起的源代码。最后我们可以将自打印程序简写为:
如果我们把一个计算机程序<math>X</math>的描述(或者称源代码)写为<math>\lambda(X)</math>,则自打印程序的第一条赋值语句就相当于给<math>q</math>赋予了<math>\lambda (Copy_o \ Popup_o \ Control)</math>,即<math> (Copy_o \ Popup_o \ Control)</math>这三个程序连在一起的源代码。最后我们可以将自打印程序简写为:
我们可以进一步地把它简写为:<math>Q(q)</math>,其中<math>Q</math>表示(<math>(Copy_o \ Popup_o \ Control)</math>)这三个程序的联合程序,而<math>q</math>则表示联合程序的源代码。<math>Q(x)</math>这个程序的作用是输出一个特殊的字符串“<math>X(x)</math>”即程序<math>X</math>调用自己的代码x的源程序,我们称这个<math>Q</math>为'''蒯恩函数'''。
我们可以进一步地把它简写为:<math>Q(q)</math>,其中<math>Q</math>表示(<math>(Copy_o \ Popup_o \ Control)</math>)这三个程序的联合程序,而<math>q</math>则表示联合程序的源代码。<math>Q(x)</math>这个程序的作用是输出一个特殊的字符串“<math>X(x)</math>”即程序<math>X</math>调用自己的代码x的源程序,我们称这个<math>Q</math>为'''蒯恩函数'''。
那么,自打印程序不是别的,正是将蒯恩函数<math>Q</math>自己的源代码再喂给它自己,这样就产生了<math>Q(q)= \” Q(q) \” </math>的效果。等式左边是<math>Q</math>对<math>q</math>的计算,是一个动作,它的结果产生了等式右边的字符串"<math>Q(q)</math>",而这个字符串恰恰就是<math>Q</math>作用于<math>q</math>的源代码。我们看到,第2节中的蒯恩方法与这里的<math>Q(q)</math>是一模一样的。仔细想想不难发现,其实自打印程序的逻辑与蒯恩语句的逻辑是相通的。因此,自指恰恰就隐藏在了这段自打印程序之中了。
那么,自打印程序不是别的,正是将蒯恩函数<math>Q</math>自己的源代码再喂给它自己,这样就产生了<math>Q(q)="Q(q)" </math>的效果。等式左边是<math>Q</math>对<math>q</math>的计算,是一个动作,它的结果产生了等式右边的字符串"<math>Q(q)</math>",而这个字符串恰恰就是<math>Q</math>作用于<math>q</math>的源代码。我们看到,第2节中的蒯恩方法与这里的<math>Q(q)</math>是一模一样的。仔细想想不难发现,其实自打印程序的逻辑与蒯恩语句的逻辑是相通的。因此,自指恰恰就隐藏在了这段自打印程序之中了。
我们只要对这个自打印程序稍加更改就能创造出自我复制的程序出来。首先,我们要说明程序的自我复制究竟是什么意思。假设内存中漂浮着很多大大小小的程序,某一个程序P能够自我复制是指,当CPU执行到程序P的时候,P就会命令CPU执行一系列的操作使得它自己的一份拷贝会出现在内存中。但是,需要强调的是P不能够从硬盘上读取文件,否则自我复制将变得异常简单,只要把硬盘上的源程序再调用到内存中就行了。乍一看,这似乎与自打印程序一样不可能实现。但是利用与自打印程序同样的蒯恩技巧,我们依然可以很轻松地构造出自复制的程序出来。
我们只要对这个自打印程序稍加更改就能创造出自我复制的程序出来。首先,我们要说明程序的自我复制究竟是什么意思。假设内存中漂浮着很多大大小小的程序,某一个程序P能够自我复制是指,当CPU执行到程序P的时候,P就会命令CPU执行一系列的操作使得它自己的一份拷贝会出现在内存中。但是,需要强调的是P不能够从硬盘上读取文件,否则自我复制将变得异常简单,只要把硬盘上的源程序再调用到内存中就行了。乍一看,这似乎与自打印程序一样不可能实现。但是利用与自打印程序同样的蒯恩技巧,我们依然可以很轻松地构造出自复制的程序出来。