webdancer's Blog
Scala学习--Program Paradigm
Program Paradigms
- Imperative Programming: modifying mutable variables, assignments, control structure;
-
Fuctional Programming:
- Strictly, No mutable variables, No assignments, No loops.
- Widely, Focusing on functions, function is the first citizens
- logical programming
理解过程抽象
在学习编程的过程中,一个核心的任务是编写可以完成我们任务的函数。不管我们使用的什么语言,做什么开发,函数抽象并不少见。所谓的函数,我认为就是一些语句的集合,完成一个特定的任务。有了函数,我们思维时的操作原子型的层次变的比较高,思维的难度就会降低。但是在不同的编程实践中,为了完成任务需要的编写函数的思维方式也许是不同的,这会受到编程语言或是第三方库的影响。
在面向对象编程中,想得是如何构建类以及如何设计类之间的关系,充分利用对象的特性,例如在使用Java编程中,会想着如何设计Class,使用什么样的设计模式,这时候函数抽象的层次依赖与我们的类设计。在使用C这样的编程语言时,使用面向对象的设计,还是直接使用函数用来模块化,也会带来不同的设计函数的思维方式。使用像Lisp这样的函数式编程语言时,我们的思维与过程式的编程语言的方式可能会有很大的不同,函数就处于核心地位了。编程的思维可能会受到我们学习过的很多东西的影响,正如上面我陈述的。我的经验是学会抽象和使用语言提供的高层抽象,这样会大大的减低我们抽象函数的难度,使我们的注意力集中到解决我们的问题。通过自己的抽象和语言提供的高层抽象来实现层次化。
下面我使用不同的编程语言实现了冒泡排序,体会一下编程语言对我们思维的影响。
对冒泡排序,我还是比较熟悉的。算法的基本思想就是:两个指针i,j,i控制每次冒泡一遍的bubble的位置,j控制每一边冒泡时要比较的数的位置,两次循环就行了。
C语言实现:
#include<stdio.h> void swap_int(int * a, int * b){ int tmp=0; tmp=*a; *a=*b; *b=tmp; } void bubblesort(int * a,int n){ int i; int j; for(i=0;i<n-1;i++){ for(j=n-1;j>i;j--){ if (a[j]<a[j-1]){ swap_int(&a[j],&a[j-1]); } } } }
在写这段代码时,我饭的错误就是给`swap_int`传递实参的时候没有取地址,这就是我对`C`语言的思维的盲区,对于`a[j]`与`a+j`我没有他们不同的认识。
python实现
def bubblesort(l): n=len(l) for i in range(n-1): for j in range(n-1,i,-1): if l[j]<l[j-1]: l[j],l[j-1]=l[j-1],l[j]
显然`python`要比C短的多,但这不代表我没有出错,因为有一段时间没写代码了,所以对`range(a,b)`的区间表示方式到底用了`[a,b]`还是`[a,b)`已经有点模糊不清了,所以就出了错。当然这种基本的问题,我们应该很明确的,但是尽管如此,我还是出错了。
java实现
public class BubbleSort{ public static void sort(int[] l){ int n=l.length; for(int i=0;i<n;i++){ for(int j=n-1;j>i;j--){ if(l[j]<l[j-1]){ swap_int(l,j,j-1); } } } } private static void swap_int(int[] l,int m,int n){ int tmp=l[m]; l[m]=l[n]; l[n]=tmp; } }
尽管`java`代码已经很久没写了,但是`java`与`c`的过程太相似了,基本没有费功夫,这里就是感觉java只有传值的参数传递方式的原因,`swap`函数一点也不优雅。
scheme实现
(define (bubblesort l) (let ((n (vector-length l))) (map (lambda (i) (map (lambda (j) (if (< (vector-ref l j) (vector-ref l (- j 1))) (swap l j (- j 1)))) (range (- n 1) i -1))) (range 0 n 1)))) (define (swap l a b) (let ((tmp (vector-ref l a))) (vector-set! l a (vector-ref l b)) (vector-set! l b tmp))) (define (range low high step) (if (or (and (> step 0) (> low (- high 1))) (and (< step 0) (< low (+ high 1)))) () (cons low (range (+ low step) high step)))) (define l (vector 2 3 1 5 4 7 8 9 1)) (bubblesort l) (display l)
写`scheme`代码,因为最近在看`SICP`,所以代码的错误只是笔误,变量名写错这样的原因,可是我还是没能使用函数式的编程方式来写这段代码,主要就是函数式编程就要使用辅助的空间,所以使用了赋值操作。
从上面的过程中我有这么几个总结:
- 过程抽象对于我们解决问题,非常有用。使用高级语言提供的机制,可以大大解放我们的编程效率。
- 理解问题的时候,通常没法子一下理解的很好,所以在对问题的理解上,要多花功夫。
- 在写过程式的语言时,对于一些地方很模糊,这就是我们训练的地方。
- 函数式的编程方式,对思维的训练量很大。
思维是一个逐渐完善的过程,我们不能期望它一下子满足期待,要循序渐进的推进。要不断的训练,并且反馈,也许我们才会有一个比较好的抽象函数的能力,不管是面向对象编程还是函数式编程。
“代码大全”读后感
“我们的精神品德既非与生俱来,也非逆于天性,...,其发展归因于习惯,...,我们要学的东西都通过实际做的过程学到,...,如果人们建的房子好,他们就成为好的建设者;而造的房子不好时,他们就是差的建设者,...,所以小时候养成怎样的习惯关系很大——正是它会造成天壤之别,或者说就是世上所有差异之源。” ——亚里士多德
代码大全旧的内容很多,交给了我们许多软件工程中的解决写软件过程中难题的解决办法。因为自己还没有接触过大型的项目,对于其中的一些并没有很强的共鸣,不过我相信在以后的工作中还是很有用的。下面就简单说一下自己的看书感受:
- 编程需要经验的传授。就像是武侠小说里面一样,一个大侠要练成绝世武功,要么像张无忌一样,偶然的机会得到了像《九阳真经》这样的武功秘籍,要么像郭靖一样,有洪七公这样的前辈教授。他们无不是从前人那里继承了技能和经验,自己发明一门武功的人真的少之又少,编程和练武也一样,很多良好的编程技巧需要学习,代码大全详细的记录了各种技巧,小到如何定义变量名,大到如何管理一个大型的软件项目,都给出了许多建议,这对我们大学生来说,还是挺有用的,很多东西,老师都没讲过。
- 编程是一个渐进的过程。很多时候,我们拿到问题就开始编写代码,这通常并不好。因为一个问题的解决从来都不是那么容易的,而且直接写代码,我们通常需要花费好几倍的时间来调试代码。编程的时候,我们可以先想一下我们要解决的具体问题,首先把问题搞明白,然后再写伪代码,这样我们用自然语言的方式先大体回答了我们要解决的问题(要是在软件工程中,就是一个需求分析,系统设计的过程),然后我们在开始将伪代码转化成代码,这个过程由于前面我们已经解决了很多东西,在这时候我们可以专心写代码。
- 编程需要的东西很多,我们需要逐渐积累。就像建筑师,要积累设计经验一样,我们程序员也要注意积累经验。现在由于搜索引擎太好用了,需要的时候可以搜索,对于很多东西缺乏思考。
- 编程需要好的编程环境和工具。良好的编程工具会极大的提高编程效率,所以一定要为自己选择一个良好的编程环境。
- 这本书是一部大块头,需要的时候翻翻,要一下子消化所有的东西不可能。