1701066370
1701066371
然后加一条指令将程序的名字打印出来:
1701066372
1701066373
program copy
1701066374
1701066375
print(“program copy”)
1701066376
1701066377
指令print只是简单地将引号之间的字符显示到屏幕上然后换行。现在增加一条指令将第二行打印出来:
1701066378
1701066379
program copy
1701066380
1701066381
print(“program copy”)
1701066382
1701066383
print(“print(“program copy”)”)
1701066384
1701066385
因为要输出程序自身的完整复制,第二个print指令的引号中带了第一个print指令前的四个缩进符和后面的一对引号(print指令输出最外侧的引号之间的所有字符,包括引号)。现在又要加一条指令来输出第三行:
1701066386
1701066387
program copy
1701066388
1701066389
print(“program copy”)
1701066390
1701066391
print(“print(“program copy”)”)
1701066392
1701066393
print(“print(“print(“program copy”)”)”)
1701066394
1701066395
现在你可能已经看出来,这种策略——每条指令输出上一条指令的拷贝——是如何导致无穷反复的。怎样才能避免这种情况呢?在继续往下读之前,你可以花点时间自己试一试能不能解决这个问题。
1701066396
1701066397
这个看似简单的问题其实关系到第4章介绍过的哥德尔和图灵的工作。解决方法同时也包含了生物系统本身绕开无穷反复的基本途径。20世纪匈牙利数学家冯·诺依曼在研究一个更复杂的问题时,首先发现了这个问题的答案。
1701066398
1701066399
冯·诺依曼是量子力学、经济学等多个领域的先驱,也是最早设计电子计算机的人之一。他的设计中包含中央处理单元和可以存储程序和数据的随机存取存储器。这些至今仍然是现代计算机的基础。冯·诺依曼也是最早深刻认识到计算和生物之间联系的科学家之一。他在生命最后的岁月里一直致力于解决机器如何才能复制自身的问题。他给出了第一个能自我复制的机器的完整设计。我在后面展示的自复制计算机程序就是受他的“自复制自动机”启发,并以简化的方式阐释其基本原则。
1701066400
1701066401
在介绍自复制程序之前,还要先解释一些会用到的编程语言的相关知识。
1701066402
1701066403
参考图8.1给出的计算机存储器示意图。在我们高度简化的例子中,计算机存储器由有编号的位置或“地址”组成,图中编号为1—5,依次往后。各位置中有一些字符。这些字符可以作为程序的指令或程序使用的数据。如果执行当前存储的程序,会显示输出:
1701066404
1701066405
Hello, world!
1701066406
1701066407
Goodbye.
1701066408
1701066409
1701066410
1701066411
1701066412
▲图8.1 计算机存储器简化示意图,位置用1—5依次编号,其中4个存储有程序。指令指针指向计算机当前存储的指令。有些指令行前面带有空格,在执行的时候会被忽略
1701066413
1701066414
要执行程序,计算机要有一个“指令指针”——同样存储在存储器中的一个数字,记录当前执行的指令在存储器中的位置。指令指针——简记为ip——最初设为程序第一行的存储地址。我们称之为“指向”那条指令。在计算的每一步ip指向的指令会被执行,ip加1。
1701066415
1701066416
例如,在图8.1中,ip的值为2,也就是说指向的是print(“Hello, world!”)。
1701066417
1701066418
我们称ip为变量,因它的值随着计算的进行而不断变化。
1701066419
[
上一页 ]
[ :1.70106637e+09 ]
[
下一页 ]