更改

无编辑摘要
第173行: 第173行:  
所谓的程序自打印就是指一个程序能够在'''不读取外部文件'''的条件下把自己的源代码打印出来。首先,我们要先领教一下,一个自我打印的程序是多么不可能的!我们知道,要写一个程序打印出“helloworld!”字样是非常容易的,例如:
 
所谓的程序自打印就是指一个程序能够在'''不读取外部文件'''的条件下把自己的源代码打印出来。首先,我们要先领教一下,一个自我打印的程序是多么不可能的!我们知道,要写一个程序打印出“helloworld!”字样是非常容易的,例如:
   −
<code>Print(‘helloworld!’)</code>
+
<pre>Print(‘helloworld!’)</pre>
    
注意在这个程序中,字符串都用单引号括起来。那么,我们能不能写一个程序,把这个打印“helloworld!”程序的源代码打印出来呢?这也是可以办到的,例如下面的程序:
 
注意在这个程序中,字符串都用单引号括起来。那么,我们能不能写一个程序,把这个打印“helloworld!”程序的源代码打印出来呢?这也是可以办到的,例如下面的程序:
   −
<code>Print(‘Print(\’helloworld!\’)’)</code>
+
<pre>Print(‘Print(\’helloworld!\’)’)</pre>
    
注意,这里面的“\’”会被编译器解释为一个字符串,这个字符串中就有一个字符:“ ` ”。采用这个技巧,我们就可以解决如何在一个引号之中再输入一个引号的问题了。所以,我们可以很轻松地打印出这个能够打印”helloworld!”程序的程序源代码出来。但是很显然这个程序并不能打印出它自己,也许你会想到能不能打印出上面的程序源代码出来?当然可以!
 
注意,这里面的“\’”会被编译器解释为一个字符串,这个字符串中就有一个字符:“ ` ”。采用这个技巧,我们就可以解决如何在一个引号之中再输入一个引号的问题了。所以,我们可以很轻松地打印出这个能够打印”helloworld!”程序的程序源代码出来。但是很显然这个程序并不能打印出它自己,也许你会想到能不能打印出上面的程序源代码出来?当然可以!
   −
<code>Print(‘Print(\’Print(\\\’helloworld!\\\’)\’)’)</code>
+
<pre>Print(‘Print(\’Print(\\\’helloworld!\\\’)\’)’)</pre>
    
其中\\就表示包含一个字符“\”的字符串变量,这样Print(‘\\’)就会打印出一个字符“\”,而Print(‘\\\’’)就会打印出字符串“\’”出来。所以,引号里面可以放入任意层次的引号。
 
其中\\就表示包含一个字符“\”的字符串变量,这样Print(‘\\’)就会打印出一个字符“\”,而Print(‘\\\’’)就会打印出字符串“\’”出来。所以,引号里面可以放入任意层次的引号。
第187行: 第187行:  
但是这个程序仍然不能打印自己!你很快发现,我们人类是写不出这种能够打印自己的程序的,因为它包含了无穷递归。不过,通过蒯恩技巧,实际上我们完全可以写出来一个自打印程序,如下:
 
但是这个程序仍然不能打印自己!你很快发现,我们人类是写不出这种能够打印自己的程序的,因为它包含了无穷递归。不过,通过蒯恩技巧,实际上我们完全可以写出来一个自打印程序,如下:
   −
<code>
+
<pre>
 
S(x){
 
S(x){
   
q=’S(x){\\nq=\\\’\’+q+\’\\\’;\\nPrint(\\\’\’+p(q)+\’\\\’);\\n}’;
 
q=’S(x){\\nq=\\\’\’+q+\’\\\’;\\nPrint(\\\’\’+p(q)+\’\\\’);\\n}’;
   
Print(‘S(x){\nq=\’’+q+’\’;\nPrint(\’’+p(q)+’\’);\n}’);
 
Print(‘S(x){\nq=\’’+q+’\’;\nPrint(\’’+p(q)+’\’);\n}’);
   
}
 
}
</code>
+
</pre>
    
<div style="text-align: center;">源代码1:自打印程序源代码</div>
 
<div style="text-align: center;">源代码1:自打印程序源代码</div>
第201行: 第198行:  
这里面的“\n”表示换行符,即如果执行<code>Print(‘A\nB’)</code>,则程序会输出下面的字符串:
 
这里面的“\n”表示换行符,即如果执行<code>Print(‘A\nB’)</code>,则程序会输出下面的字符串:
   −
<code>A</code>
+
<pre>
 
+
A
<code>B</code>
+
B
 +
</pre>
    
“+”表示将两个字符串进行串联形成一个新的字符串,例如<code>A=’123’,B=’456’,则A+B=’123456’</code>。
 
“+”表示将两个字符串进行串联形成一个新的字符串,例如<code>A=’123’,B=’456’,则A+B=’123456’</code>。
第228行: 第226行:  
如果我们把一个计算机程序<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>这三个程序连在一起的源代码。最后我们可以将自打印程序简写为:
   −
<code>
+
<pre>
 
S(x){
 
S(x){
   
q= λ (Copy<sub>o</sub> Popup<sub>o</sub> Control)
 
q= λ (Copy<sub>o</sub> Popup<sub>o</sub> Control)
   
(Copy<sub>o</sub> Popup<sub>o</sub> Control)(q);
 
(Copy<sub>o</sub> Popup<sub>o</sub> Control)(q);
   
}
 
}
</code>
+
</pre>
    
<div style="text-align: center;">源代码2:自打印程序的源码缩写</div>
 
<div style="text-align: center;">源代码2:自打印程序的源码缩写</div>
第269行: 第264行:  
那么我们只要这样修改S(x)就可以了:
 
那么我们只要这样修改S(x)就可以了:
    +
<pre>
 
S(x){q=’S(x){\\nq=\\\’\’+q+\’\\\’;\\nF(\\\’\’+p(q)+\’\\\’);\\n}\\nF(x){\\nPrint(length(x));\\n}’;
 
S(x){q=’S(x){\\nq=\\\’\’+q+\’\\\’;\\nF(\\\’\’+p(q)+\’\\\’);\\n}\\nF(x){\\nPrint(length(x));\\n}’;
 
F(‘S(x){\nq=\’’+q+’\’;\nF(\’’+p(q)+’\’);\n}\nF(x){\nPrint(length(x));\n}’);
 
F(‘S(x){\nq=\’’+q+’\’;\nF(\’’+p(q)+’\’);\n}\nF(x){\nPrint(length(x));\n}’);
第275行: 第271行:  
Print(length(x));
 
Print(length(x));
 
}
 
}
源代码4:计算自己代码长度的计算机程序
+
</pre>
 +
 
 +
<div style="text-align: center;">源代码4:计算自己代码长度的计算机程序</div>
    
注意,红色的代码部分就是在上一个代码的基础上添加的。这样,此程序不仅包含了S(x),而且还包含了一个附加的程序F(x)的定义,并且这个附加函数F(x)的源代码也需要被包含到之前F()之中和q的赋值语句之中。运行这个程序,它就会在屏幕上打印出自己源代码的长度。
 
注意,红色的代码部分就是在上一个代码的基础上添加的。这样,此程序不仅包含了S(x),而且还包含了一个附加的程序F(x)的定义,并且这个附加函数F(x)的源代码也需要被包含到之前F()之中和q的赋值语句之中。运行这个程序,它就会在屏幕上打印出自己源代码的长度。
匿名用户