说明:本文是备课稿,可能缺少足够细节和深入推敲
在一个神奇的星球上有一只小猪叫拉丁,它有自己的语言Latdin,Latdin非常有趣但难懂,比如它经常 这么说话:
owHay oday ouyay oday?
iceNay otay eetmay ouyay!
这是什么意思?后来一位人类发现,拉丁的语言都是模仿人类的,只不过经过了一些加工:
- 一个词如果以元音字母(a e i o u)开头,就在词尾加上“ay”,比如“Oh”变成“Ohay”
- 一个词若以辅音字母开头,则所有第一个元音字母前的辅音(如有多个)都移到词的后面,然后再加上“ay”
- 对于全由辅音字母构成的单词,原封不动。
原来,刚才那两句是在问候人类:
How do you do?
Nice to meet you!
好吧,那这和计算有什么关系?
首先计算(computing)涉及状态改变(注1),我们都知道数学上的函数y=f(x),在x取值范围内输入一个x,输出对应的y。这个x叫变量,输入x之后,x可能发生改变并被输出,也可能在函数(想象成“黑箱”)内部新出现了一些w、z之类的变量跟x一起发生变化最终形成结果。还有其他可能,但就算x的值在这个函数内不发生变化,输出结果也不是x本身了,而是一个与x有关的返回值。
输入:一段人类语言
输出:一段Latdin语言
第二,刚才奇怪的Latdin语言包括一套计算规则,用于进行状态改变。而且这个规则还不简单,有足足3条。所有的计算都涉及规则,没有规则我们无法进行计算。y = 2*x (x∈ R)中“乘以2”就是一个规则,而且这个规则还有附加条件即x是实数。
然后,计算设计数据到信息、数据和信息之间的转化,我们可以把刚才的例子加以补充分别以输入和输出的形式列下:
Oh. Ohay.
Hi, amigo! iHay, amigoay!
How do you do? owHay oday ouyay oday?
What's your name? at'sWhay ouryay amenay?
Nice to meet you! iceNay otay eetmay ouyay!
上面的过程可以高度抽象成 “字符串 → 字符串”这个过程,如果我们细看字符串的内部,发现可以再分成 “单词 → 单词”和“单词 → 句子”这个过程。这是形式变化。
语义变化是什么?第一种语言是人类能理解的,第二种是小猪拉丁能理解的,如果对小猪直接说“How do you do?”它不能直接理解,但“owHay oday ouyay oday?”就能理解了,而对于人类呢,要把它的话翻译成人能理解的形式。
数据本身是无意义的,比如刚才的词和句子被归入“字符串”这个概念,但我们可以从中提取信息,信息是我们所需要的,常常具体数据在信息获取后失去价值。另一方面,信息需要合适的数据结构来表示,字符串、数字、布尔值、数组、图、栈、队列都是数据结构,复杂数据结构是由原始数据结构构成的。
我们会在以后陆续了解各种数据结构以及设计和实现它们的方法,现在只需要理解一个例子:
现在有原始数据结构“字符”,包括所有拉丁字母和常用标点符号、空格。接下来我拿出“H”“e”“l”“o”这四个字符,把它们放到一起,其中“l”用两次,变成“H-e-l-l-o”(中间破折号用作区分不包括在字符里),于是一个新的数据产生了,大部分人类都会自然意识到它代表了“你好”的信息,没错,信息就是通过结构化的数据表现的。
通过把字符组织到一起,我们得到了字符串。
同时我们发现“How do you do?”和“owHay oday ouyay oday?”有对应关系,那现在能不能找到一种工具让二者进行转化呢?
有两种让两种语言进行转换的方法,第一种是应用规则。
假设我们不知道人类语言如何转换成Latdin,但我们知道有人知道,那就可以去问这个聪明人。很幸运,得到的结构就是开头列出的那3条规则,非常明晰。
当我们知道了这些规则就可以使用它们,一种使用方法是人工应用,我们可以用刚才的规则把“ni hao”转化成“inay aohay”,另一种在当代计算中使用更多的是使用计算机来实现。
计算机是一类机器的统称,它们有一个共同特点是可编程。编程是编写程序的意思,程序跟规则有密切的关系,但大部分程序是把规则明确、直接地写入一种叫计算机语言的特殊语言,这种语言是专门为计算机理解的。
在这个页面里https://c.runoob.com/compile/9 点击运行,注意左侧输入框的第二行即可,把刚才那段删掉,改成
def addString(input):
return input+"ay"
print(addString("Hi"))
再运行。我们刚才定义了一个函数,叫addString,它接收input作为参数,把input加上“ay”之后作为结果返回它执行的地方,然后通过一个系统自带的函数print将“Hi”作为参数的函数应用的结果输出来。
目前我们的知识和对工具—编程语言的了解还不足以边写整个实现那3条规则的程序。然而实现这3条规则的完整程序与刚才这小段程序没有本质区别,这小段程序与控制航天器、显示网页的软件(更“复杂”的程序)也没有本质区别。
另一种让人类和Latdin语言转换的方法是:获得更多(许多许多)人类语言和Latdin对应的例子,除了之前列出的还要有:
"Owh" Owh
"My name is Ladtin." My amenay isay adtinLay.
"Good Bye." oodGay eByay.
"I am happy." Iay amay appyhay.
……
然后,有另一种程序,它所做的是通过两种语言大量的对照数据,发现这三条规则,然后找更多的对照数据,等它足够信心了就宣布自己成功发现了规则,然后把规则应用到新的人类语言用于输出对应的Latdin。
听起来像归纳法的意思,但机器,计算机能做到如此复杂的归纳吗?
此外,需要多少数据?为什么不直接找到规则。
实际上这两种程序早在现代的电子计算机诞生之前就都存在了,很长一段时间内人们以为第一种是计算的主要形式,甚至是唯一形式。后来人们意识到第二种的重要性,比如有时候规则是隐藏在数据中的,就算能表达成人类能理解的形式也过于复杂。比如股票价格,股票价格受时间等很多因素影响,但至今没有人类能直接定量预测,然而已经有了基于大数据进行股票价格预测的程序。还比如称为图像识别的东西,根据很多标明内容的图片去判别新的图片。
那如何开发这样一种从数据中“挖掘”出信息甚至规则的程序呢?这个我们现在的相关知识的还有限,但可以确定的是这种程序和第一种程序没有本质区别。
-----------------------选讲部分----------------------
另一个体验程序设计的角度是计算的任务形式,流式还是批处理的。
第一种计算过程是围绕数据流——把所有输入的数据按最小单位进行且分后排在一起,然后每新得到一点数据(小块)就进行一点计算,直到数据都输入完了,计算也很快随之结束。
第二种计算过程是把所有数据一起拿来,然后分成一些小块,每个计算单元(比如机器)得到一些,这些计算单元多数情况下使用相似甚至相同的方法对自己得到的小块进行计算,然后把结果汇总到一起。
以按规则的计算方法为例,如果是流式计算,可以一个字符一个字符地处理字符串所代表的句子,比如“How do you do?”得到H,是辅音,存在一个“缓冲对象”中留作后用,然后o和w得到保留,再往后遇到了空格,说明第一个单词结束了,这时候把刚才“缓冲”了的H拿出来加到后面,然后再加上“ay”,然后再看“d”……。
批处理呢,先把“How do you do?”分成“How”、“do”、“you”、“do”和“?”「严格来说那3条规则没照顾好句中符号的情况,但为了演示方便忽略」,各个单词分别进行处理,然后和句尾符号加到一起。
这两大计算任务形式与计算机一样古老,与规则/数据为中心的两种计算方式交融并存,我们会在以后的学习中逐步深入了解。
注:
- 著名计算机科学家Edsger Dijkstra的代表作A Discipline of Programming前言中提到计算就是状态改变。
- 我把第一种解决方案用Java编程语言写了出来,链接 供有编程经验的同学和专业人士参考、批判。
- 本文的例子源于一个编程入门教程