谈谈编程语言(三)——好的编程语言

  

        编程语言有两个作用:

        一,程序员指挥计算机的工具。

        二,程序员表达思想的媒介。

        《计算机程序的构造和解释》的前言中写道,“一个计算机语言并不仅仅是让计算机去执行操作的一种方式,更重要的,它是一种表述有关方法学的思想的新颖的形式化媒介。因此,程序必须写得能够供人们阅读,偶尔地去供计算机执行。”很多人忽视了第二个作用,而作者把第二个作用看得比第一个还要重要。我目前则介于中间,对我来说,操纵电脑和表达想法同等重要。

        这是两个极端,一个语言更靠近机器或是相反决定了它的抽象程度。一般来说靠近机器的语言更难表达思想,比如用Assembly来面向对象(object-oriented)可以是可以,但是很难读懂。同理Java一句a.eat()也可能让CPU跑很多个周期。时光倒流50年,不难想象当时的编程语言多么追求效率。然而在经过过去这摩尔定律(Moore's law)有效的几十年之后的今天,还有人跟我说因为Python效率低而不用之,实在不敢苟同……

        我的观点很明确,好的编程语言应该易写,易读,高度抽象,让程序员能够随心所欲(这个词夸张了-_-)地表达自己的思想。至于效率则不是那么重要的因素。试想一下哪些工作真正需要计算机超高的效率?分解DNA,模拟核爆,以及计算明天早上会不会下雨。虽然我不知道确切比率,不过地球上随便挑一百万个人出来,其中的生物学家,物理学家和气象学家加起来也不会超过几百个吧。而满足大部分人需求的应用程序则根本不需要太高效率,因为人是分辨不出0.01秒和0.001毫秒之间的差别的。

        好~那么在效率和表达思想上如何取舍呢?再次搬出那个经典的快速排序(quick sort),每一次把列表中第一个元素作为基准(pivot)进行分派,这是最简单快速排序。

C版本:

void swap(int *a, int *b) { 

  int temp = *a; 

  *a = *b; 

  *b = temp; 

}

 

void quicksort(int arr[],int beg,int end) {

  if (end  >= beg + 1) {

    int pivot = arr[beg], k = beg + 1, r = end;

    while (k < r)  {

      if (arr[k] < pivot) 

        k++;

      else

        swap(&arr[k], &arr[r--]);

    }

    if (arr[k] < pivot) {

      swap(&arr[k],&arr[beg]);

      quicksort(arr, beg, k);

      quicksort(arr, r, end);                    

    } else {

      if (end - beg == 1)

        return;

      swap(&arr[--k],&arr[beg]);

      quicksort(arr, beg, k);

      quicksort(arr, r, end);                  

    }

  }

}


 

        看上去还不错,非常典型的C程序

Python版本:

def quicksort(items):

 if not items: return []

 pivot = items[0]

 return quicksort([x for x in items[1:] if x < pivot]) + \

   items[0:1] + quicksort([x for x in items[1:] if x > pivot])


 

        呃……事实上给pivot赋值的那一行纯粹是为了可读性,return那一行也断句了,否则Python版本的快速排序只有3行,C程序员看上去可能觉得短得像作弊。

Scheme版本:

(define (filter pred seq)

  (cond ((null? seq) '())

        ((pred (car seq)) (cons (car seq) (filter pred (cdr seq))))

        (else (filter pred (cdr seq)))))

 

(define (quick-sort items)

  (if (null? items)

      '()

      (let ((pivot (car items))

            (rest (cdr items)))

        (define greater? (lambda (x) (> x pivot)))

        (define lesser? (lambda (x) (< x pivot)))

        (append (quick-sort (filter lesser? rest))

                (cons pivot (quick-sort (filter greater? rest)))))))


 

        我先定义了一个过滤器filter,用于分派,然后把分派出来的表进行排序,最后再合并。事实上稍微熟悉Python和Scheme的人就能看出来,上面那两段代码几乎是一样的……Python的列表推导式(list comprehension)其实就是个过滤器(filter)。

        对比一下,这三段代码运行效率最高的肯定是C,因为C的代码就在原先的数组上操作,没有作多余的事,Python和Scheme都要递归而不断产生了新的表,所以就慢下来了。然而我在写Scheme和Python的时候都感觉得到脑子里几乎只有算法,自然而然的把代码敲出来了。写C的排序的时候,满脑子里却想着内存不要越界~显然C语言分散了程序员的精力,不同语言表达思想的能力高下立判。

        另外从可读性看,Python和Scheme由于代码更像是人的想法,刚接触Scheme的时候,我都觉得C代码很dirty(-_-没别的意思,不过在这方面,Ruby可能更抢眼~Ruby的拥护者们都宣称Ruby代码就像英语一样可以大声念出来)。不过有个有意思的地方,Lisp/Scheme虽然抽象级别很高,但毕竟它的起源不是人,而是【数学】,所以并不是很接近人的思维。相比之下Python和Ruby倒是更像人的语言。

        除了能表达程序员的思想,好的语言还应该具有两个特质:一,能轻易分解和组合程序;二,能轻易构造关于问题的语言。这些实际上也都是方便程序员的特点,一方面提高重用性和模块化,另一方面抽象程度更高。

        其实这篇文章的标题很模糊。我真正想表达的意思是,对程序员好的编程语言。而不是对解决问题好的编程语言。但是我认为计算机发展到今天,这两个概念发生交集的概率越来越大。在以前,对解决问题好的定义更多指的是能够让计算机高效的将结果计算出来。现在,天平在慢慢向程序员倾斜。一个语言如果有利于程序员思考,那么更有可能对解决问题有好处,而不必考虑太多效率的问题。

        我无意说C语言可以死了,事实上目前为止还没看到这种可能性。不过程序员们是否应该在效率不这么重要的场合来更多的尝试一下那些好的编程语言呢?

 
——TT
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值