初识函数式编程和Lisp之后的一点感想
me.ThisBlog.Goal = “引起一些大家对函数式编程的关注和对面向对象地位的反思”;
me.ThisBlog.Style = “侃大山”;
if (you.Expectation == “看到一篇技术博客”)
{
return null;
}
ReadBlog();
return you.Comments;
void ReadBlog()
{
写完《你以为你了解面向对象设计么?》,鬼使神差地看了一些文章,使我对函数式语言产生了极大的好奇。
- 首先,在博客园“面向对象”栏目,紧接着我那篇随笔,有个网友转发了InfoQ上的一篇文章“对象已死?”。
- 其次,在“读书区”看了博客“《黑客与画家》:出身于大牛程序员的风险资本投资家的随想录”,于是我也买了本《黑客与画家》看。先看了后半部分关于编程语言的几篇文章,如:一百年后的编程语言、梦寐以求的编程语言、书呆子的复仇、拒绝平庸,等等。
- 最后,有位网友在评论我那篇随笔说:“When CMU is trashing OOP, you are starting learning it.”(当卡内基梅隆大学“扔”掉OOP的时候,你却开始学习它),并附了一个InfoQ上关于“卡内基梅隆大学计算机科学系把OOP从一年级新生的介绍性课程中去掉转而增设函数式语言课程”的链接。
说“鬼使神差”,是因为这几件本不太相干的事情最终都指向了同一样东西,那就是函数式编程(Functional Programming,有人简写为FP)以及它和面向对象编程的关系(注:函数式(Functional)和面向对象技术本不是同一层面的概念,和函数式相对的应是命令式(Imperative),但因其牵扯进不少面向对象技术的问题,所以引起本人注意)。这极大地促使我想去了解函数式语言。
在这些资料中,说得比较多的就是Lisp语言(当然,还有Haskell, F#, Erlang等)。其实,早在上世纪80年代,本人看到过一本讲述Lisp语言的中文书,翻过几页。现在模模糊糊想起来,当时的感觉有两点:一、看不懂,没有BASIC容易学(本人那时候上中学,学校教BASIC);二、没用,所以在后来的某个日子里,当旧书卖掉了。现在使我比较惊讶的是,为什么一个在1958年创造的编程语言,有如此强的生命力,如今它所代表的函数式编程大有“要取代面向对象技术成为主流方式”的趋势。
“为什么Lisp语言如此先进”从专业的角度介绍了为什么Lisp很特别,网上还有不少介绍Lisp语言的文章,大家可以参考这些内容初步了解这种语言。我作为一个门外汉,初识Lisp,觉得以下内容还是挺使我惊奇的。
- 语言的内核设计的非常小。Lisp语言只有7种公理(基本操作符)。
- 写出来代码很短。30多行的代码,就可以写一个Lisp方言的解释器。据说C代码平均是Lisp代码的7到10倍,还有说20倍的。
- 为什么Lisp代码更短?就是因为使用“自下而上”的编程方法。你不是在基础语言上开发,而是在基础语言上构件一种你自己的语言,然后再用后者开发。
- 你要是不能想象Lisp语言的代码是什么样,可以试着想象XML,想象XML中的每个节点都是函数和自变量,而且可以执行。(Lisp的代码都是嵌套和递归的,编译后就是一颗解析树。没有数据和代码之分,而且是动态类型语言。)
- 我在08年学习C#时候才知道的垃圾回收机制,Lisp语言在1960年就引入了。
- Lisp在所有语言里,具有最高的抽象层次,编程能力最强,。(这里的抽象指编程语言本身的抽象,不是对待编程物的抽象。)
- Lisp没有过时的原因是因为本质上它不是一种技术,而是数学。数学是不会过时的。
- 皮特诺维格发现,总共23种(面向对象的)设计模式中,有16种在Lisp语言中“本身就提供,或被大大简化”。
确实有点吓到我了。如此强大,面向对象岂有活命的道理。所以带着学到的仅有的一点点知识,开始在其中寻找面向对象的生存空间。所幸,还有些收获。
- 面向对象语言更接近人的自然语言。虽然CMU说OOP是Anti-Modular和Anti-Parallel的,但不可否认OOP具有自然性(Naturality)。如果计算5x2,Lisp写成“(* 5 2)”(*相当于函数名,5和2是自变量)。另外,下面这段Lisp代码,你能大概看出它是干什么的吗?
(defun assoc (x,y)
(cond ((eq (caar y) x) (cadar y))
(‘t (assoc x (cdr y)))))
这里可能会引入一点争论,到底代码是写给谁看的?是写给机器“看”的?还是写给人看的?我认为最终是写给人看的,所以我更看重语言的自然性。
- 面向对象技术还有很好的可重用性和可扩展性。这一点,即使是List的大师Paul Graham也不得不承认。所以,如果你需要可持续性的开发,可能面向对象技术是合适的选择。
- 也许上面2条比较片面。因为我在用自己擅长、且长期使用的语言来看待自己不会、且有重大差异的语言,思维定式可能会误导我。那么我们用函数式语言的大师和专家的说法来看看。《对象已死?》一文中提到CLOS(Common Lisp Object System,一套用Lisp编写嵌入在Lisp中的系统),根据Paul Graham在《On Lisp》一书中所述:“CLOS 的到来似乎意味着Lisp 正在改变自己,以拥抱面向对象的编程方式。与其这样说,不如改成:Lisp 还在墨守成规,用老样子来拥抱面向对象编程,这样还确切一些”,无论他怎么说,我们可以看出函数式编程是可以和面向对象编程共存的。在CLOS里定义一个Circle类,可能是这样的:
(defclass circle ()
((radius :accessor circle-radius :initarg :radius)
(center :accessor circle-center :initarg :center)))
而创建对象实例可能是这样的:
(circle-radius (make-instance ’circle
:radius 2
:center ’(0 . 0)))
上面这些代码相当于:
public class Circle
{
public Circle(float radius, PointF center)
{
_radium = radius;
_center = center;
}
public float _radius;
public PointF _center;
}
class Program
{
static void Main(string[] args)
{
Circle circle = new Circle(2, new PointF(0, 0));
Console.WriteLine(circle._radius);
}
}
所以,面向对象有其生命力,也许它会进化,也许会和函数式融合,但它不会在100年内消亡(之所以用100年来说,是因为受Paul Graham的“一百年后的编程语言”文章影响)。但尽管如此,我等喜爱面向对象技术的人,还是不应固步自封,还是应该跳出面向对象编程的圈子,去了解和接触函数式编程。
P.S. 本人初识Lisp和FP,以上内容如有任何谬误之处,敬请指正。谢了!
}