Lisp的给力特性(V.S. Python3) -- 第一篇


BS,Gosling,Anders,Guido都要被打屁股?
以前就听说过Lisp被很多人认为是世界上最好的语言 ,但是它是那么的古老,这种言论很可能来自于不能进化到学习Ruby,Python的老古董,所以其实也没有太在意。
Lisp(这里特指Common lisp,下同)1978年被设计完成,是个多么古老的语言啊。。。。却总是不停的听到太多的Lisp的好话,总是感觉有些难以相信,BS说,"一个新设计的语言不比老的好,那新语言的设计者是要被打屁股的 ",假如Lisp还是世界上最好的语言,那么从BS自己,到James Gosling到Anders到Guido van Rossum 不都要被打屁股啊? 你说我能轻易相信吗?
“如果我们把流行的编程语言,以这样的顺序排列:Java、Perl、Python、Ruby。你会发现,排在越后面的语言,越像Lisp。 ”这个话 真的可信吗?
正好碰到一篇妄图说服我的文章《Features of Common Lisp》,眼见为实,是骡子是马,跑起来看看^^本文以Features一文为线索,(标题翻译的不好,请童鞋们见谅)与Python作为对比,C++啥的就都不太好意思拿出来比了,因为总是可以以效率为理由搪塞过去,但是,有可能我还是顺带提及一下。但是,总的来说,这是在Lisp的领地上战斗,,C++,Python是很吃亏的,但是作为已经足够强大的语言,还能够自我革新,Python的最新版本(3.1.1,以下没有特指,均指此版本)能够怎么应付,我拭目以待。特别提及,相比Lisp实现,CPython的运行速度慢得惊人,甚至差5-10倍,对于一个牺牲速度来换取表达性的语言,要是比不过速度比自己快那么多的语言,实在有些说不过去,即使是在别人的地盘..........迎战的Lisp是lispbox-0.7版本中集成的common lisp。

Lisp特性列表
强大抽象的数学计算(Rich, exact arithmetic):

大数(Bignums ): 不用当心溢出。
Lisp:
CL-USER> (expt (expt (expt (expt 10 10) 10) 10) 10)
100000000000000000000000000000000000...

这个貌似还行,C++虽然是需要通过外部库来处理,(在新标准中有过关于大数的提案,我以前还翻译过一篇《(N1744)Big Integer Library Proposal for C++0x 》)
但是Python对大数的支持还是非常不错的,特别提及,在Python2.1时代,虽然有大数支持,但是你得自己指定,假如都是用普通整数,还是会溢出。在2.2以后版本中已默认会进行类型提升。(参考PEP237 )呵呵,这点挺符合越新的语言(在Python来看,也就是越新的版本越接近)也就是越接近Lisp的理论。

Python:
>>> ((((10 ** 10) ** 10) ** 10) ** 10)
1000000000000000000000000000000000000000000 .....

分数(Rational numbers ): 保留成比例的形式。
Lisp:
CL-USER> (+ 5/9 3/4)
47/36

这个很牛很牛。。。。我目前懂的语言,(C/C++,Lua,Python,Objc以后提及均表示此意)还没有哪个是这样计算分数的,给你的都是浮点数。
特别提及一点,在Python2.x时代,上面的整数运算会像C++中那样,直接变成整数(5/9也就是0),但是新版本中已经不那么扭曲了。

Python 2.6.4:
>>> 5 / 9
0

Python3:
>>> 5 / 9
0.5555555555555556
我很遗憾的表示,同样的,python3比2.X版本更加像lisp,但是还不是足够像。

 

复数(Complex numbers ):
内建支持

Lisp:
CL-USER> (* 2 (+ #c(10 5) 4))
#C(28 10)

这个也还算方便,虽然我平时好像也用不上,C++中得通过库处理。Python也内建支持。

Python:
>>> (((10 + 5j) + 4) * 2)
(28+10j)

相对来说,以近似伪码著称的Python表达还是更加清晰一些。

统一的引用(Generalized references):
Lisp:
CL-USER> (defvar *colours* (list red green blue))
*COLOURS*
CL-USER> (setf (first *colours*) yellow)
YELLOW
CL-USER> *colours*
(YELLOW GREEN BLUE)
CL-USER> (push red (rest *colours*))
(RED GREEN BLUE)
CL-USER> *colours*
(YELLOW RED GREEN BLUE)

Lisp的操作都是使用引用对列表进行操作,你可以改变这个列表,实际操作的是同一个列表,就像你使用了rest操作,并对其进行push,但是实际也还是会改变原来的colours,因为rest返回的也还是引用而不是临时变量,这个特性看起来很有意思,有些特殊,具体的使用范围我还不是太清除(因为毕竟没有lisp编写大型的程序)

 


比如:

 


Python:

>>> l
[red, yellow, green, blue]
>>> l ;
[red, yellow, green, blue]
>>> l = ["red", "green", "blue"]
>>> l[0] = "yellow"
>>> l
[yellow, green, blue]
>>> l[1:]
[green, blue]
>>> l2 = l[1:].insert(0, "red")
>>> l2
>>> l
[yellow, green, blue]

 


需要注意的是,l[1:].insert(0, "red")操作是不会返回[red,green,blue]的,这样你临时的变量都获取不到,同样的,用切片操作来模拟的话,不仅没有返回值,原列表更不会改变,因为切片后的是临时变量,而不是引用。

 

多重值(Multiple values):
Lisp:
CL-USER> (floor pi)
3
0.14159265358979312D0

有简单的内建语法支持多个值,因此能方便的让函数返回多个值。此点C++就靠其他手段吧,比如异常ugly的用传指针/引用,然后再通过指针/引用传出去,虽然用了这么多年的C++了,这种方式也习惯了,但是一比较,就知道那不过是个因为语言的抽象能力太弱,使用的walk round的办法而已。 Python还是可以的。
虽然,Python的floor不返回两个值。

Python:
>>> import math
>>> math.floor(math.pi)
3

但是,你的确是可以返回多个值。

Python:
>>> def myFloor(x):
    return math.floor(x), x - math.floor(x)

>>> myFloor(math.pi)
(3, 0.14159265358979312)

但是,需要特别注意的是,这只是个假象......因为实际上是相当于将返回值作为一个tuple返回了。

Lisp:
CL-USER> (+ (floor pi) 2)
5

在计算时,让第一个多重值的第一个变量作为计算的变量,所以非常方便。

因为Python的返回值如上面所言,其实是用tuple模拟多个返回值的,不要奢望了。

 


Python:

>>> myFloor(math.pi) + 1
Traceback (most recent call last):
  File "<pyshell#58>", line 1, in <module>
    myFloor(math.pi) + 1
TypeError: can only concatenate tuple (not "int") to tuple

 


不过,lua倒是可以,可能lua还是从lisp那吸收了很多东西吧:

 


Lua(5.1.2以下同):

> math.floor(math.pi)
> print(math.floor(math.pi))
3
> function myFloor(x)
>> return math.floor(x), x - math.floor(x)
>> end
> print(myFloor(math.pi)+ 1)
4


而且在Lisp中可以很方便的使用多重值的第二个值。(通过multiple-value-bind)

 


Lisp:

CL-USER> (multiple-value-bind (integral fractional)
         (floor pi)
       (+ integral fractional))
3.141592653589793D0

 


Python因为返回的是tuple,指定使用其他值倒是很方便,包括第一个(虽然不是默认使用第一个)

 


Python:

>>> myFloor(math.pi)
(3, 0.14159265358979312)
>>> myFloor(math.pi)[0] + myFloor(math.pi)[1]
3.141592653589793

 


最后,即使这样Lisp在表达方面还是有优势的,因为在lisp中floor只计算了一次,而python的表达方式得多次计算,除非起用临时变量。

 

宏(Macros):
lisp的宏有点像其他语言中的函数,但是却是在编译期展开(这就有点想inline的函数了),但是在Lisp的fans那里,这被称作非常非常牛的syntactic abstraction (语法抽象),同时用于支持元编程,并且认为可以很方便的创造自己的领域语言。目前我不知道到底与C++的宏(其实也是一样的编译期展开),还有比普通函数的优势在哪。(原谅我才学Lisp没有几天)

LOOP宏(The LOOP macro):
Lisp:
CL-USER> (defvar *list*
       (loop :for x := (random 1000)
          :repeat 5
          :collect x))
*LIST*
CL-USER> *list*
(441 860 581 120 675)


这个我有些不明白,难道在Lisp的那个年代,语言都是循环这个概念的。。。。导致,循环都是一个很牛的特性?

继续往下看就牛了

 


Lisp:

CL-USER> (loop :for elt :in *list*
        :when (oddp elt)
        :maximizing elt)
675

 


when,max的类SQL寻找语法

 


Lisp:

CL-USER> (loo

相关内容

    暂无相关文章

评论关闭