SumireHina Ri0n72Y Code Farmer, Idea/Trash Creator

计算机科学的基本问题(1)

» 开发

接近毕业,同时正值新生入学季。这个系列(如果不拖坑)会以一种非常主观的方式总结介绍什么是计算机科学。如果给新入计算机科学的你带来帮助,那就再好不过。


计算机科学的基本问题 The Fundamental Questions of Computer Science

每个学科都有其对应成立的原因,一个或一系列的问题促使人们将解决方案和寻找解决方案的方法论归纳起来,便成了一个值得学习研究的学科。

计算机科学有这么几个基本问题:

  • 可计算性
    • 一个问题,判断其是否可以被计算(已经被搞定了)
    • 研究这个问题该怎么被计算(主要工作)
  • 计算机如何解决问题
    • 如何让机器解决数学问题(已经被搞定了)
    • 如何把现实问题(real-life problems)变为数学问题(大学在教的东西)

当然,上面这些东西对于刚从高中出来的学生是没有意义的。我们更可能会提出这些问题:

  • 我为什么要用计算机来解决问题?
    • 要解决什么问题?
    • 为什么要解决问题?
    • 有什么问题人解决不了需要计算机解决?
    • 计算机能解决什么问题?
  • 那,什么是计算机?和计算器有啥不一样吗?
    • 计算机怎么解决问题?
    • 什么是编程?
    • 为什么要编程?
    • 编程能赚到多少钱?
  • 好的,我已经完全掌握了,那,从哪里开始?

跳跃一段时间,假设你已经学完了大学四年。你会发现上述问题几乎都是无意义的。但即使如此,这些由直觉问出的问题仍然非常重要,它是我们认知一个领域的开始,你会发现将关键词“计算机”换成任一学科都会适用。沿着 YJango大佬 提议的认知学习方式,我们从直觉来对计算机这门学科认知。

要解决什么问题?或者说,有问题吗?我觉得现在过得挺好

如果你对历史感兴趣,那你一定熟知工业革命以及之后的变化。工人们涌上街头,声称“机器抢走了我们的工作”。对于一个在工场体系下进行重复劳动的工人来说,干活领工资的生活对他来说挺好的,没有问题。当然,这篇文章不打算探讨无产阶级的局限性,我们只考虑发现问题本身。提升产量,良品率,降低成本是从工场升级为工厂的必要过程。而自动化是在这一过程中的必经之路,即使用机器代替人类(需要注意的是,对于流水线来说机器不是必需品,人组成的系统也可以是流水线,机器是时期效率提升的手段,而且并不总是提升效率)。解决自动化问题是提升生产力的关键,如果你对马克思的政治经济学还有印象的话,人类社会的发展就是生产力的发展–这句话应该还记得。虽然它被过度简化而且槽点很多,但仍然不失其正确性。

自动化问题,最贴近考试成风的高中就是机器阅卷了。虽然学生们没有体感,但确实减少了大量老师的负担 – 至少他们不需要盯着 ABCD 对照着正确答案拿笔一个一个圈了。当然,自动化阅卷也给老师带来了麻烦,这是设计系统时的失误,并不代表着自动化不行。

另一个自动化问题就是推荐算法。我们每个人的偏好不同,拿到一份报纸或杂志,每个区域关注的信息和投入的时间也不甚相同。设想没有自动化推荐,那我们就需要一群编辑坐在办公室里,给不同的人组织不同的内容投放 – 这带来的成本还不如我继续缩小报纸上的字,以便塞下更多的内容从而吸引更大范围的阅读者来的便宜。

计算机在自动化中的角色,它使得之前无法提供自动化方案的问题变得可解了。最早的计算机是木制手摇的,用于自动求解方程。这非常神奇:只需要将几个转盘转到位,答案自己就出来了!而这个过程中的机械结构的设计,我们就将它叫做算法 – 这个词将来会大量出现。算法比现代意义上的计算机出现要早得多,它是数学数理逻辑的一个分支。这个领域的大佬:邱琦,图灵,哥德尔,奠定了现代计算机的基础。其中图灵机定义了这样一个东西,它将我们面临的所有自然事件定义为状态,一件事,一个物品或者一个系统的变化可以被看做是从一个状态转移到另一个状态,其中转移这一过程,如何定义转移就是研究算法。解决问题对于图灵机来说,就是从当前的状态转移到我们期望的状态,计算机所做的所有事情都可以被这么概括。

状态转移,好的,似乎到了很玄学的地方

通过把问题定义为状态转移,我们就能够使用图灵机 - 或者称呼为计算机 - 来解决这些问题。这里我们使用一个日常的场景来举例解释状态和状态转移。

做红烧肉

给你一口好锅,一个带开关的燃气灶,一台抽油烟机,一把切肉刀,一块砧板,一个炒菜铲,一个很能干的厨师,一瓶料酒,一瓶酱油,一盒盐,一盒糖,一壶水,一块上好的五花肉,一个盘子,一个水池附带水龙头和下水系统,均匀地码在厨房里。如何做出一道红烧肉?

[1] 所有东西都分开摆好,我们将这个厨房中现在所有上述东西的行为和状态,定义为我们当前的状态,即初始状态。

好吧,首先,这些东西实在是太多太杂了,我甚至都没办法记住我有什么。我能不能简单地给他们归个类?

[*] 很聪明的想法,不妨试试这样,这是其中一种归类方法:

厨房:{
    厨具:{
        锅:一口好锅,
        刀:一把切肉刀,
        砧板:一块砧板,
        菜铲子:一个炒菜铲,
        盘子:一个盘子
    }
    设备:{
        灶:一个带开关的燃气灶,
        抽油烟机:一台抽油烟机,
        水池:一个水池附带水龙头和下水系统,
    }
    材料:{
        肉:一块上好的五花肉,
        水:一壶水,
        盐:一盒盐,
        糖:一盒糖,
        料酒:一瓶料酒,
        酱油:一瓶酱油,
    }
    厨师:一个很能干的厨师
}

你给这些东西归了类(class),并且简单地分了层级。我们待会用的时候找起来就会很方便,比如我:

[2] 拿起 厨房.厨具.刀,把 厨房.材料.肉 放在 厨房.厨具.砧板,让 厨房.厨师 执行 切块() 动作;

这和:

[3] 拿起 一把切肉刀,把 一块上好的五花肉 放在 一块砧板 上,让 一个很能干的厨师 执行 切块() 动作;

是等价的。

这两行字看起来已经离人类有了一点距离。

如果执行了上述动作,那么我们的整体状态就发生了变化:

厨房:{
    厨具:{
        锅:一口好锅,
        刀:一把切肉刀,
        砧板:一块砧板,
        菜铲子:一个炒菜铲,
        盘子:一个盘子
    }
    设备:{
        灶:一个带开关的燃气灶,
        抽油烟机:一台抽油烟机,
        水池:一个水池附带水龙头和下水系统,
    }
    材料:{
        肉:没了 //曾经是一块上好的五花肉,
        切好的肉:一份切好的五花肉丁,
        水:一壶水,
        盐:一盒盐,
        糖:一盒糖,
        料酒:一瓶料酒,
        酱油:一瓶酱油,
    }
    厨师:一个很能干的厨师
}

你当然也可以用 厨房.材料.肉 称呼那份已经被切好的肉,比如:

厨房:{
    ...
    材料:{
        肉:一份切好的五花肉丁, //曾经是一块上好的五花肉,
        ...
    }
    ...
}

这是等价的,只是你叫它的方法不同。但总而言之,我们的状态从初始状态,转移到了现在这个状态。只要我们按照一定顺序去执行一系列的动作,最终我们会用掉所有材料,并且在厨房里放上一份 盛在盘子里的红烧肉

那么我们期待的最终状态是:

厨房:{
    厨具:{
        锅:一口好锅,
        刀:一把切肉刀,
        砧板:一块砧板,
        菜铲子:一个炒菜铲,
    }
    设备:{
        灶:一个带开关的燃气灶,
        抽油烟机:一台抽油烟机,
        水池:一个水池附带水龙头和下水系统,
    }
    材料:{},// 用完了
    菜:盛在盘子里的红烧肉,
    厨师:一个等待夸奖的厨师
}

这样一来,只要我们给一个动作序列,就可以让一台机器自动地指挥整个厨房系统工作,并且最终获得期望的结果。

如果你看过其他图灵机相关的资料,不难发现,厨房开始的设置就是初始状态 p0, 动作序列就是图灵机的状态机状态转移 ,最终会在做出红烧肉后停机。而我们所谓“程序员”的任务,就是设计并实现这个图灵机的动作,即我们所说的一般意义上的程序。