像计算机科学家一样思考是什么意思呢?为了回答这个问题,我会退一小步,提出一个听着很有哲理的问题。
什么是知识?
我假设知识可以分为两个大类
陈述性的知识
程序性的知识
什么是陈述性知识呢?
用叙述事实来思考它,它描述一个真相。
例如:X的平方根是Y。所以Y的平方等于X。Y是正数。
这是一个定义,这个就是陈述性的知识,它不能帮助你具体算出2的平方根是多少。它没说具体怎样计算。具体怎样计算就是程序性知识要做的事情了。程序性知识是对推论过程的描述。
给一个程序性知识的小例子:
假设有一个g,如果g的平方接近于X,停止,然后回到g
If g的平方接近X stop return g
这个方法是一系列行动的描述。注意它包含了什么?它包含了我按顺序所定下的具体指令。我会按顺序进行一些测试。按照测试的数值,我会改变指令序列中我的位置。这个方法让你知道怎样寻找平方根。这是一个关于怎么办的知识。它就是程序性知识。这基本上就是计算相关的东西。我们希望能有办法捕捉到这里面的过程。
那么我怎么才能建立计算机程序,去捕捉一系列的计算呢?我们假设有个很容易的方法能做到这点。一个方法是,你可以想像在这儿建造一个环形线路,如果我有几个存着数值的元素,用导线把他们移来移去,我就会有一部分做加法。一部分做减法。一部分做检查。我能建造一个小线路来进行这个计算。虽然听上去蛮奇怪的,但这就是最早的计算机的一个例子。因为最高的一代计算机就是我们所称的“固定程序计算机”。意思是它们拥有为进行特定计算而设计的小线路。
例如我们日常使用的计算器,它基本上是固定程序计算机的一个范例。它可以做计算,如果你想用它玩游戏那就没办法了。事实上很多早期的有趣的玩意儿都与其类似。例如,Atanasoff( 1941年问世),这是由一个叫做Atanasoff的人设计出来的早期计算器中的一个,基本上解决线性方程租的问题。还有一个我最爱的早期计算机,由图宁设计用于二战中破译德军代码的bombe也是固定程序计算机。
但固定程序计算机并不能让我们到达我们想去的地方。我们需要能自己改变游戏规则的计算机。
这就是存储程序计算机
在一个存储计算机里有一个程序,这个程序允许执行我们希望他执行的指令。
在一个存储计算机里,我们会有如下的组成部分:
我们有一个存储器,这个存储器连接两个单元,控制单元(Control)和算术逻辑单元(ALU),ALU有输入和输出。我们还有指令系列,它们都存储在存储器里,指令被当做数据来对待。它在机器的存储器里面,我们可以读取它,编辑它。另外还有一个程序计数器。这就是计算的基础。程序计数器指示存储器当中的某些位置,它从存储器中取出两个位置的结果,在倍增器中运行,再将它们插回存储器中的某些地方去。或者从存储器中取出一个结果,在类似的操作中运行,再插回到存储器中。执行过这个指令之后,计数器加1,于是我们移动到下一条指令。最终你可能会停下来。一个结果运算出来,你就完成了。
这就是计算机的核心
我想让你们了解到的就是,程序就是指令序列。假设我有一系列指令,比如我有一系列描述所有东西的初始指令。我能建立什么?
举个栗子:我将6个鸡蛋分开,击打蛋清直到它们黏黏的为止。将蛋黄取出。加上糖和面粉,把它们混合成别的东西。这里面有一个步骤,一个传统的菜谱是建立在一小堆的原材料和一个好厨师之上的。根据那个原材料,好厨师可以创造出无数的美味佳肴来。编程也是如此。给出一组固定的类型,一个优秀的程序员可以编出任何程序来。
目前至少有几百种编程语言存在,我认为没有最好的语言,每种语言有它最适合的用途,但是我们需要一种语言来帮助我们理解。在这里我们会用Python,Python是一种不错的新型语言。但我们不是要讲Python,我们只是学会如何用Python思考问题。我们主要是做设计“菜谱”的事情。
一种语言有三种维度需要提及:
1、你能有多靠近机器的核心呢?
一个低级语言,我们只是把一些数据碎片从记忆存储器中的一个地方通过简单的操作来转到另外一个地方。
一个高级语言,设计者制造了丰富的原始要素。在一个高级语言中,平方根可能只是你使用的一个基本要素。而不是你去编程。两者之间各有利弊。
2、这个语言的目标群体是比较大众还是有特定面向群体的?
这个语言是支持比较多的程序,或者是面向某一种特定种类的程序的。我认为MATLAB是有特定处理对象的语言。它主要面向矩阵和向量等。
3、这个语言是编译语言还是解释语言?
如果是解释语言的话,你要写一些叫做源码的东西,你写的东西会经过一个简单的过滤器,然后解释器会处理你的源码。解释器会产生一个逐条读取你源码的控制流。然后返回一个输出结果。因此解释器在运行程序的时候,会对你的代码进行操作。
而在编译语言里,你会经过一个中间的步骤。在这种语言里输入源码后,先经过过滤器或者编译器检查后,它会创建一个叫做目标代码的东西。这有两点好处,第一是可以帮助你发现程序中的Bug,第二是可以把你的代码在运行之前转化成更有效率的指令的集合。在两种语言中我们要做一个平衡,解释语言调试起来很容易,因为你可以看到最原始的代码。但是这种语言不快。编译语言更快一些。
Python是一种高级语言,是一种面向比较广的语言。它处理字符串比处理数字更有效率。它在运行前捕捉错误不是那么优秀。边运行边调试会更容易一些。
在Python下怎么去写代码呢?我们的目的是得到一个问题,然后将问题分解为这些计算步骤。像自然语言一样,我们要去把语法和语义区分开来。语法是这个语言的合理表示是什么?语义分为static语义和full语义,static语义主要说哪些程序语法是正确的吗?full语义就是程序有什么意义?即当我们运行它的时候会发生什么?
Python语言里面自带有会检查你的语法的东西,它一次会找出一个Bug,所有你们必须要有点耐心。大多数的错误会在运行时被捕获,问题是,你在这个阶段捕获的是隐患最小的bug。他们很容易被捕捉到,你没法带着这些错误去运行程序。但并不是所有的错误都会在静态语义检查中被捕获。你的程序依然会返回一个值。但是这个值可能不是你想要的。这就需要我们建立一个良好的编程风格来避免这种错误。
下面讲Python,我们需要值或者基础的数据类型来创建。我们从两个类型开始说起。一个是数字,另外一个是字符串。字符串在Python中是以一个开引号开始的,然后后面是一系列的字符。以一个尾引号结束。在Python中每种类型都对应着一种数据类型。类型确定了对象的种类。一些很明显。字符串就是一种单独的类型。
数字有很多种类型:整形,浮点型等等。对于每种类型都有和之对应的一个操作集,这个操作集对一些输入做出规定的操作,然后鉴于输入类型返回结果输出。为了说明这些内容,我们先下载一个Python实际操作一下。
下篇文章讲Python。
待续
领取专属 10元无门槛券
私享最新 技术干货