理解计算的本源,学习记录集:学习思路

时间:2021-12-26 00:11:38

    先回顾下过去半年来的过程:

    被要求从WP7开发平台转到Android平台-->

    但是个人不喜欢Java语言,感觉Java对程序员的限制多,把程序员当笨蛋似的 -->

    经常上infoq, cnblogs, 51CTO等网站,得知JVM Languages,最被看好的Scala编程语言 -->

    开始学习和Scala Console下的编程实践,开始“谷哥”(从不用“度娘”)函数式编程相关介绍 -->

    wiki,博文,专题,论坛,etc

    初步的学习了一段时间后,心里的问题:

    1,函数式编程中,函数是第一等的,体现在什么地方?这里的“函数”和C/C++/JAVA/C#中的“函数/方法”有什么区别?高阶函数是什么意思?编程时怎么用?有什么好处?

    2,函数式编程和面向对象编程有什么关联?OO过时了?

    3,稍微看下,就找到函数式编程的根源:Lambda表达式。还好我写过 Emacs Lisp的代码,语法上不陌生,但是还是不能说得上理解。这个Lambda表达式和图灵机等价,厄,什么意思?图灵机,有限状态机,概念上早就知道了,但是它们是怎么被发明的?用在什么地方?,并不清楚。(大学里学习的知识,往往只知道what,而不知道how和why,这是因为不是从实际需要去主动地学习,自然谈不上真正的理解。)

    前2个问题,我在《理解计算的本源,学习记录集:编程语言发展趋势,函数式编程》中做了基本的思考和总结,文中也有很多学习链接。此文可以算是我学习函数式编程的第一篇总结。

    但是第3个问题,我就止步了,因为要去学习理论的东西,艰深的让人生畏。But,它一直放在我心里,我只是暂时放一下,不着急,以后慢慢“啃”。

    到此的心得小结如下:

    1,函数式编程思想根源于Lambda演算,这其实是专业的数学领域内容,而且由来已久,一开始就是学院派的产物,比计算机的诞生还要早

    2,它之所以没有被比C/C++/Java/C#更流行,因为它绝对不是贴近计算机硬件实现的编程语言。它有着更高层次的抽象。它和这些语言的根本不同,在于看待计算机的计算方式:是基于硬件实现的命令式(指令式),还是基于数学抽象(函数式)的描述式。这种高层次的抽象,进一步解放开发人员,把主要精力放在问题的解决上,而不是不断地告诉计算机,如何一步步的按照指令去实现。

    3,它其实和OO,不是一个层面上的东西。OO不会死亡,而它却要逐渐发挥出力量。这其实是产业界向学院界拿成果的结果。

    4,多核时代和并发计算,是让它走向前台的直接原因。

    后来慢慢想到,实际上我需要的是一些“启蒙”读物,让我能去掉畏难的心理,感受到它的power,激发学习兴趣。

    随后,我就看到了InfoQ上的一篇文章《对象已死?》。更让我高兴的是,评论中有人提到了一本书《黑客与画家(Paul Graham/阮一峰)。迅速读完,进一步加深对了Lisp编程语言的认识,对编程语言的认识,以及对计算理论的学习向往。学习到Lisp语言的9种思想,通过和Scala语言的印证,确实感觉到编程思想上的新天地!


    为什么Lisp具有这么久的生命力和强大的能力?!因为它根源于坚实的数学基础,而这短短的50多年来,其数学基础并没与什么大的发展!所以,对于软件开发人员来说,了解计算发展的历史,理解根本的东西,是多么的必要啊。实际上在实际的开发中,只要涉及到一些具有核心价值的功能,都需要很好的算法设计,即,很好的数学基础的。

    接着,进一步google"计算理论 pdf",想找资料学习。呵呵,又发现了一本好书,《图灵机与计算问题》(张江)

    此书完全可以做为计算理论的启蒙读本,用故事和实例通俗的说明了:

    1,什么是图灵机。

    2,可计算问题。

    3,停机问题。

    4,目前计算机的计算能力极限。

    个人看法,这本书非常好!所以推荐大家一定要读读上面提到的2本书!

    到此的心得小结如下:

    1,要学习计算理论,不要被它的抽象数学理论吓到,即不要有畏难情绪。也许很多人会被挡在这一步。

    2,去年正好是图灵百年,有一系列的文章介绍他,这些不属于纯技术的读物,其实对理解技术有很多帮助。很简单的,我们会问:“他当时为什么会想出来这些?本意是为了处理什么问题的?”,了解他的历史,会了解到他的思想。

    3,别只看到图灵和图灵机,其实我们还是要去看丘奇和他的Lambda表达式,这才是函数式编程语言的直接根源。

    有了兴趣,以及形象的认识(一定要看《图灵机与计算问题》(张江)),接着整理下系统点学习思路。

    目前国内的相关教科书似乎不多,我只找到二本:《计算理论基础,第二版》(张立昂),《计算理论导引》(张立昂),看来是一样的,我觉得用前者就可以了。

    通过这本书的目录,我们可知,对于学习计算理论来说,要求的数学基础并不太多。集合论是必要的,但也不用到公理系统的地步,然后就是离散数学中的一些内容。同时,根据网上的搜索,参考这里的目录,摘录如下:

1. 数理逻辑

        1.1 希尔伯特的可判定性问题以及图灵的否定证明
        1.2 哥德尔不完备性定理(这个其实之前写过,会直接引用)
        1.3 希尔伯特第十问题
2. 计算模型
        2.1 图灵机
                2.1.1 一般的图灵机以及等价模型
                2.1.2 带有oracle的图灵机
        2.2 lambda演算
                2.2.1 无类型lambda演算
                2.2.2 简单类型lambda演算
        2.3 递归函数
        2.4 组合逻辑、寄存器机等小模型
3. 可计算性理论
        3.1 停机定理,Rice定理
        3.2 Quine, Y组合子
        3.3 图灵度
        3.4 蔡汀常数
4. 应用
        4.1 现代计算机受图灵机以及lambda演算的影响
                4.1.1 计算机病毒
                4.1.2 编程语言
                4.1.3 硬件
        4.2 程序的静态分析
        4.3 自动定理证明

    所以对于逻辑学(形式逻辑-->数理逻辑),也应该学习的。这样可以得出大致的学习路线:

    1,数理逻辑。(涉及信息论的一点点认识,布尔代数等)

    2,离散数学。(集合论、关系、函数等)

    3,计算理论。

    这里要说明的是,学习是要讲效果和效率的,不是那种“哦,我要学英语了,然后就把大学本科英语第一册拿来,从第一个单词开始学起”的学习方式。牢记要学习的中心需求是什么,根据问题,逐步前进,抽丝剥茧,每一步都要多问问这个知识点是从何而来的,到了一定程度再横向扩展,打通知识点之间的联系,形成知识树和网络。

    以下面wiki链接中对函数式编程语言的解释为例,我加上注解,想到的问题:

函数式编程英语:Functional programming),又称泛函编程,是一种编程范型,它将电脑运算视为数学上的函数计算,并且避免状态以及可变数据。函数编程语言最重要的基础是 λ 演算(lambda calculus)。而且λ演算的函数可以接受函数当作输入(引数)和输出(传出值)。

    1,“泛函编程”?我知道数学上有泛函的概念,和这里有什么关系?

    2,“将电脑运算视为数学上的函数计算”,这是区别指令式编程语言的不同,思想上的不同。之前的学习,就是然给我们把计算机理解成按照一条条指令执行的机器,这种思维方式,不是“数学家看待计算机”的方式。

    3,“lambda演算”?从没接触过,完全不懂,要深入学习之。通过看wiki的链接,初步了解后,会有更多的疑惑提出来。这就开始涉及到数学专业以及计算理论的提出的历史了。

函数式的程序没有变量副作用(Side effect)。因为函数式程序设计语言没有变量,函数没有副作用,编写出的程序可以利用记忆化公共子表达式消除并发计算在运行时和编译时得到大量优化

    1,什么是副作用?

    2,没有变量?厄,对于编程来说,变量太基础了,毁三观了,怎么理解?

    函数式编程中最古老的例子莫过于1958年被创造出来的LISP了,通过 LISP,可以用精简的人力。较现代的例子包括schemeHaskellCleanErlangMiranda等。虽然 λ 演算并非设计来于计算机上运行,但可视为第一个函数式编程语言。1980年代末期,Haskell发布,企图集合很多函数式编程研究裏的想法。

    1,“通过 LISP,可以用精简的人力”,功能很强大,可以节省人力成本?体现在什么方面?

    2,“虽然 λ 演算并非设计来于计算机上运行”,这是什么意思?那最初设计之用在哪里?

    总的来说,学习过程的一些基本思路:

    1,要通过某种函数式编程语言随时实践。比如开始学习Scala编程语言,也可以直接用LISP的方言,比如Common Lisp,或者Emacs Lisp。

    2,学习到每一个概念,要反复琢磨。知道从何而来,以及应用领域,局限性,才能算的是理解。简单的说,可以用自己的话总结出来它的概念、性质和特点、涉及的主要理论等。

    3,既有纵向的逐渐深入,从果求因;又有阶段的总结,再由因到果,形成网络。这样迭代式前进。避免盲目的学,一窝蜂式的学。

    4,不断去想,不断总结。有心得就写下来,写着写着就有惊喜。甚至蹲坑的时候都会自觉地去想。这个要依赖于对此事的真正的兴趣。

    附上一些链接:

wiki:函数式编程语言

wiki:离散数学

wiki:数理逻辑

wiki:Lambda演算

编程语言背后的数学原理 (名字起的很好,但是内容不全)

lambda演算学习笔记 (提到了发展历史)

希尔伯特之梦,以及梦的破灭 (了解计算机为什么会产生的数学上的原因)

计算的极限(零):逻辑与图灵机 (下面是方弦的系列文章,可惜还没有完成,上面的目录也是他的)

计算的极限(一):所有机器的机器,与无法计算的问题

计算的极限(二):自我指涉与不可判定