更改

跳到导航 跳到搜索
添加176字节 、 2026年9月9日 (星期三)
第294行: 第294行:  
</syntaxhighlight>
 
</syntaxhighlight>
   −
它的机制很简洁:字符串 `c` 本身是一个"打印模板"——`%r` 会带上引号打印出 c 自己的内容,`%%` 是格式化转义符(输出为单个 `%`)。于是 `print(c % c)` 打印出的结果,恰好就是这个程序的全部源码。'''程序把自己的源码当作数据、再把它打印出来'''——这正是第二递归定理"程序合法地引用自己的代码"在程序语言里的最小实现。<ref name="wikipedia_quine_computing" /><ref name="kiselyov" />
+
它的机制很简洁:字符串 `c` 本身是一个"打印模板"——`%r` 会带上引号打印出 c 自己的内容,`%%` 是格式化转义符(输出为单个 `%`)。于是 `print(c % c)` 打印出的结果,恰好就是这个程序的全部源码。'''程序把自己的源码当作数据、再把它打印出来'''——这正是第二递归定理"程序合法地引用自己的代码"在程序语言里的最小实现<ref name="wikipedia_quine_computing" /><ref name="kiselyov" />。
    
'''把 Print 换成任意可计算操作 f:quine 是 SRT 在 f = Print 上的特例'''。上面那个 quine 里的 `print(c % c)` 可以立刻换成'''任意可计算操作'''。看下面这个程序——它不再"打印自己",而是"先把自己的源码施加一个变换 f、再打印结果"(这里 f = "给每一行加上行号"):
 
'''把 Print 换成任意可计算操作 f:quine 是 SRT 在 f = Print 上的特例'''。上面那个 quine 里的 `print(c % c)` 可以立刻换成'''任意可计算操作'''。看下面这个程序——它不再"打印自己",而是"先把自己的源码施加一个变换 f、再打印结果"(这里 f = "给每一行加上行号"):
第311行: 第311行:  
</syntaxhighlight>
 
</syntaxhighlight>
   −
`c % c` 仍然是"自己的源码",但最后一行不再是 `print(c % c)`,而是 `print(f(src % src))`——也就是先调用 f 处理自己的源码、再打印结果。这个程序满足
+
`c % c` 仍然是"自己的源码",但最后一行不再是 `print(c % c)`,而是 `print(f(src % src))`——也就是先调用 f 处理自己的源码、再打印结果。这个程序满足:c 的行为 = "对 c 的源码施加 f、再打印"的行为。
   −
> c 的行为 = "对 c 的源码施加 f、再打印"的行为
+
——用公式写就是 <math>\phi_c = \phi_{f(c)}</math>(<math>\phi_c</math> 是程序 <math>c</math> 当作可计算函数看时的整体行为)。把上面那个 <math>f</math> 换成别的——比如"统计字符数"、"对源码求 SHA-256(一种密码学中的哈希函数)"、"把字符串大写"、"把源码上传到某服务器"、"什么都不做只返回自己"——只要 <math>f</math> 是可计算的全函数,'''满足 <math>\phi_c = \phi_{f(c)}</math> 的不动点程序 <math>c</math> 就必然存在'''。这正是 SRT 所承诺的内容:quine 是 SRT 在 <math>f =</math> "Print" 这一个特例上的推论,SRT 则是 quine 在 <math>f =</math> "任意全可计算函数"上的推广。Kiselyov 在分阶段 <math>\lambda</math> 演算里把这一观察形式化为"quine = f = id 的不动点、twine(两程序互相打印对方)= f = 另一程序编号映射的不动点、trade 谜题 = f = 投影函数对的不动点"<ref name="kiselyov" />。
   −
——用公式写就是 <math>\phi_c = \phi_{f(c)}</math>(<math>\phi_c</math> 是程序 c 当作可计算函数看时的整体行为)。把上面那个 f 换成别的——比如"统计字符数"、"对源码求 SHA-256"、"把字符串大写"、"把源码上传到某服务器"、"什么都不做只返回自己"——只要 f 是可计算的全函数,'''满足 <math>\phi_c = \phi_{f(c)}</math> 的不动点程序 c 就必然存在'''。这正是 SRT 所承诺的内容:quine 是 SRT 在 f = "Print" 这一个特例上的推论,SRT 则是 quine 在 f = "任意全可计算函数"上的推广。Kiselyov 在分阶段 <math>\lambda</math> 演算里把这一观察形式化为"quine = f = id 的不动点、twine(两程序互相打印对方)= f = 另一程序编号映射的不动点、trade 谜题 = f = 投影函数对的不动点"<ref name="kiselyov" />。
+
'''SRT 的证明,本身就是一个 Quine 构造——而且方向和 quine 完全相同'''。再回看 §5.3 那一行证明——给定 <math>f</math>,构造 <math>\psi(x) = \phi_{S(x,x)}</math>(其中 <math>S</math> 把 <math>f</math> 与"自应用"组合起来),取 <math>e</math> 满足 <math>\phi_e = \psi</math>,再对 <math>\psi</math> 套 SRT 取不动点——会发现它和 quine 是'''同一种构造''',差别只在目的(执行层面 vs 输出层面)。两边共用同一种"自指核心动作"——'''让程序合法地把"自己的表示"当作输入''':
−
 
  −
'''SRT 的证明,本身就是一个 Quine 构造——而且方向和 quine 完全相同'''。再回看 §5.3 那一行证明——给定 f,构造 <math>\psi(x) = \phi_{S(x,x)}</math>(其中 S 把 f 与"自应用"组合起来),取 e 满足 <math>\phi_e = \psi</math>,再对 <math>\psi</math> 套 SRT 取不动点——会发现它和 quine 是'''同一种构造''',差别只在目的(执行层面 vs 输出层面)。两边共用同一种"自指核心动作"——'''让程序合法地把"自己的表示"当作输入''':
      
{| class="wikitable"
 
{| class="wikitable"
第346行: 第344行:  
|}
 
|}
   −
也就是说,'''SRT 证明与 quine 不是"互逆",而是同构'''——两者都是"先有一个具体的全可计算函数 f、再造一个不动点程序 c 满足 <math>\phi_c = \phi_{f(c)}</math>"。"quine 是 f = Print 时的特例"是对的,但"quine 是先有 f 反求 c、SRT 是先有 c 对任意 f 都成立"是错的——SRT 证明里 c '''也是''' f 的函数(换一个 f 就换一个 c)。SRT 真正比 quine 强的地方只有一点:'''它证明了"先有 f、再造 c"这种构造对所有全可计算 f 都成立''',而 quine 只演示了 f = Print 一个特例;SRT 给的不是"一个程序",而是"对每个 f 都有一个程序(f 的不动点 c)"这样的普遍性陈述。这也解释了为何 SRT 在可计算性文献中被称为"second recursion theorem"——它把"quine 这种特例的构造手法"摆到了"自指可计算函数的普遍刻画"这一位置,把 quine 从"程序员的奇技"升格为"任何合理程序系统都封不住自指"的元定理。
+
也就是说,'''SRT 证明与 quine 不是"互逆",而是同构'''——两者都是"先有一个具体的全可计算函数 <math>f</math>、再造一个不动点程序 <math>c</math> 满足 <math>\phi_c = \phi_{f(c)}</math>"。SRT 真正比 quine 强的地方只有一点:'''它证明了"先有 <math>f</math>、再造 <math>c</math>"这种构造对所有全可计算 <math>f</math> 都成立''',而 quine 只演示了 <math>f =</math> Print 一个特例;SRT 给的不是"一个程序",而是"对每个 <math>f</math> 都有一个程序(<math>f</math> 的不动点 <math>c</math>)"这样的普遍性陈述。这也解释了为何 SRT 在可计算性文献中被称为"second recursion theorem"——它把"quine 这种特例的构造手法"摆到了"自指可计算函数的普遍刻画"这一位置,把 quine 从"程序员的奇技"升格为"任何合理程序系统都封不住自指"的元定理。
   −
'''例 2(自我命名的集合)'''<ref name="rogers1967" />:是否存在程序 n,它所列出的集合恰好是单点集 {n}——'''一个枚举出自己编号的程序'''?直觉上这像是编号系统的"巧合",但取变换规则 f 使得"程序 f(x) 恰好输出单点集 {x}"(这样的 f 显然可构造),应用表述 B 即得 <math>\phi_n = \phi_{f(n)}</math>,即 <math>W_n</math> = {n}。而且这个结论对'''任何合理的程序编号系统都成立'''——它不是编号的巧合,而是编号的必然。
+
'''例 2(自我命名的集合)'''<ref name="rogers1967" />:是否存在程序 <math>n</math>,它所列出的集合恰好是单点集 <math>\{n\}</math>——'''一个枚举出自己编号的程序'''?直觉上这像是编号系统的"巧合",但取变换规则 <math>f</math> 使得"程序 <math>f(x)</math> 恰好输出单点集 <math>\{x\}</math>"(这样的 <math>f</math> 显然可构造),应用表述 B 即得 <math>\phi_n = \phi_{f(n)}</math>,即 <math>W_n = \{n\}</math>。而且这个结论对'''任何合理的程序编号系统都成立'''——它不是编号的巧合,而是编号的必然。
   −
'''自指的机制'''(Rogers 的精辟分析)<ref name="rogers1967" />:不动点程序 n 作为一段指令,'''并不包含它自身的全文'''(这不可能,句子不能比自身还长),而是包含'''一份"如何重建自身"的配方'''——"先算出我的代码,再执行它"。这与 Gödel 在证明不完备定理时发明的"替换函数"(substitution function,把一个公式的编号代入公式自身)是同一种机制。自然语言中的对应物是这个短语:
+
'''自指的机制'''(Rogers 的精辟分析)<ref name="rogers1967" />:不动点程序 <math>n</math> 作为一段指令,'''并不包含它自身的全文'''(这不可能,句子不能比自身还长),而是包含'''一份"如何重建自身"的配方'''——"先算出我的代码,再执行它"。这与 Gödel 在证明不完备定理时发明的"替换函数"(substitution function,把一个公式的编号代入公式自身)是同一种机制。自然语言中的对应物是这个短语:
   −
> "the result of substituting 'the result of substituting "x" in "x"' in 'the result of substituting "x" in "x"'"   
+
"the result of substituting 'the result of substituting "x" in "x"' in 'the result of substituting "x" in "x"'"   
−
> (把 "把 x 代入 x 的结果" 代入 "把 x 代入 x 的结果" 所得到的结果)
+
(把 "把 x 代入 x 的结果" 代入 "把 x 代入 x 的结果" 所得到的结果)
    
——按规则展开后,这个短语恰好指称'''它自己'''<ref name="rogers1967" /><ref name="moschovakis2010" />。
 
——按规则展开后,这个短语恰好指称'''它自己'''<ref name="rogers1967" /><ref name="moschovakis2010" />。

导航菜单