说一门新外语,O'Caml(之一)

本文介绍一个对大多数读者朋友来说,相信都相对比较新奇的编程语言,这就是 O'Caml。这是在 Perl 之外,又一门以骆驼为吉祥物的编程语言。不过,O'Caml 的骆驼可是很富有曼妙的诗意的啊。相信读者朋友们在经过了一番探索后,会明白这曼妙的诗意究竟是缘何而来。还有,据说,O'Caml 可是真正挑剔的程序员的首选编程语言哦。

本文中,作者使用了台湾计算机作家侯捷先生倡导使用的一些翻译名词。比如,把 Type 翻译成"型别",而不是"类别",因为 Class 一次被翻译成"类",这样可以避免含糊;又比如,Function 翻译成"函式",而不是"函数";Argument 翻译成"引数",而不是"实参"等等。希望读者朋友们不会觉得"怪怪的"。说实话,作者还是比较赞同侯先生的。

赵蔚 (zhaoway@public1.ptt.js.cn), 自由职业者

赵蔚,自由职业者。专业从事 Linux 及 Open Source 的咨询业务。喜欢 Tori Amos,Alanis Morissette,Bjork,PJ Harvey 还有 Suzanne Vega。



2002 年 7 月 01 日

为什么又要学习一门新的编程语言呢?

为什么呢?不过,学习一门新的编程语言难道真的是很难吗?呵呵,也许真的是这样的吧。但是,对于我们这些程序员来说,学习一门新的编程语言可是一件很大开眼界的事情啊。而且,即使我们不想学习新的编程语言,新的编程语言也是蜂拥而来,真的是很没有办法的事情。不仅仅是像 C# 和 Java 这样通俗的新的编程语言,而且,读者朋友们经常可以在一些专用的场合,看到一门又一门的从没有见过的新的编程语言。学习一门新的编程语言的能力,可以说,已经成为一名程序员所必须的"生存"能力之一了。而培养这个能力的最好办法,难道不就是开始学习一门新的编程语言吗?

而且,学习一门新的编程语言,可以说,是开始探索计算机科学的庞杂知识体系的一条好路子。一门又一门的新的编程语言,从各自不同的角度,为我们打开计算机科学的一个又一个的新视界。只有通过编程语言,我们才可以和计算机进行交流。和计算机进行交流的这个唯一的渠道,难道不是最值得我们这些程序员的重视吗?


为什么要选 O'Caml 呢?

哈哈,那我再讲讲 O'Caml 的"酷"吧。

首先,O'Caml 不是像 Java 或者 C# 那样,是一门非常热门的不得了的编程语言。读者朋友们要问我了,难道这也算是优点不成?是啊,当然!"随大溜"难道是一流的程序员干的事情吗?

呵呵,认真的说,O'Caml 还是非常的流行的,但是 O'Caml 的流行是通过程序员的众口相传,而不是通过那些铺天盖地的广告。

其次,O'Caml 宣称自己是给真正挑剔的程序员使用的。有些编程语言可不是这样哦,他们一开始就宣称自己是设计起来给"大路货"的程序员使用的。这实在是有伤自尊啊!那些真正好的编程语言,比如 C,Perl,Smalltalk,Lisp,都是设计者设计起来给自己用的编程语言。给自己用的!读者朋友们请想一想,就算设计者再高明,她或他明确的设计起来给"大路货"的程序员使用的编程语言,和大师们设计起来给自己用的编程语言相比较,恐怕是好不到哪里去的吧。

第三,O'Caml 的动机很好,它是为了研究 Functional Programming 而设计起来的。而不是为了商业利益而产生的编程语言。第四,O'Caml 有一个曼妙无比的骆驼做它的吉祥物。读者朋友们到 O'Caml 的主页上去看看就知道了。第五,没有人强迫你使用 O'Caml。你的老板只会强迫你使用,呵呵,你不喜欢的编程语言。


见面握一握手

好啦,玩笑话说到这里,下面来讲讲 O'Caml 到底是怎么一会事吧。O'Caml 是面向对象的 Caml 语言。而 Caml 则是 ML 的一种法国方言。ML 还有其它的方言,最有名的可能要数 Lucent 公司旗下大名鼎鼎的贝尔试验室开发的 Standard ML of New Jersey,如果有机会,我们今后也可以介绍一下这个蛮有趣的 SML/NJ 的。话说回来,O'Caml 是一种自动侦测型别(Type)的 Functional 编程语言。所谓 Functional 系列的编程语言,它们最重要的特征之一,就是用 Functional 编程语言写出来的程序几乎没有边界效应。

在 O'Caml 中,一个例程,或者说一个函式(Function)是这个编程语言中所谓的第一等的公民。何谓"第一等(Fisrt Class)的公民"?就是说,在 O'Caml 中,函式可以像一个 int 或者 float 一样被很方便的传递来传递去。这也就是所谓"Functional 编程语言"中,Functional 一词的由来。

O'Caml 又有一个很强的型别系统。有多态(Polymorphic)和型别自动侦测(Type Inference)的功能。强的型别系统,配上型别自动侦测,这是 O'Caml 区别于 Lisp 的很重要的一点。

模式匹配。对于习惯用 C 语言这一系列的编程语言的读者朋友们来说,模式匹配实在是一种稀奇古怪的编程方法。不过,用起来倒是很爽的说。说起来,这有点像一个过分增强了的 Case 语句。

支持 Exception 和自动内存管理。说到支持 Exception,读者朋友们要是了解 Lisp 特别是 Scheme 中的 Continuation 这个概念的话,会觉得和 Continuation 比起来,这一套不太过瘾。如果以后有机会,我也希望向大家介绍一下 Scheme 这个 Lisp 方言。有人宣称,这个 Continuation 概念是计算机科学中的一个最大的发明之一。不过,呵呵,我们还是先回到 O'Caml 上来吧。至于自动内存管理,也就是所谓的垃圾收集,现在大家都司空见惯了。

哦,别忘了,O'Caml 还有很强的面向对象的功能。毕竟,O'Caml 中的那个"O"就是指的面向对象的支持嘛。

这些东东,我们会在后文一一展开,详细说明的,读者朋友们请不必太过着急。关于 O'Caml 和其它编程语言之间进行的详细的比较,我们也会在这一系列文章快要结束的时候进行。好啦,这就正式开始我们的 O'Caml 之旅吧。

哦,对了。O'Caml 可以在 Linux 和 Windows 还有 Mac OS 9 以及 Mac OS X 上跑,是免费的开放源代码的自由软件。而且,O'Caml 有一个非常令人满意的 Library。如果读者朋友们想要进行跨平台的开发的话,O'Caml 是一个非常不错的选择。在我们往下进行之前,读者朋友们可以先去 O'Caml 的主页上下载一个 O'Caml 的环境。这样,我们下面讲起来的时候,读者朋友们可以在一边动手练习,学习起来也方便一些。


到处走一走看一看

我们先来看一个求阶乘的小程序。注意,下面行首的"#"符号,是 O'Caml 命令行环境的提示符。O'Caml 当然也可以让你在文本编辑工具中写你的大部头程序,然后再编译运行。不过,我们现在为了学习起来方便,在 O'Caml 的交互式的命令行环境下工作。

# let rec fact n = if n<2 then 1 else n*fact(n-1) ;;
val fact : int -> int = <fun>
#

上面我们定义了一个 fact 函式。注意看到,O'Caml 用";;"终结一个语句。这一点作者也是不很感冒,但是";"在 O'Caml 中另有妙用,所以也没有什么办法。著名的 Alan J. Perlis 说过,"Syntactic sugar causes cancer of the semicolon."这也是没有办法的事情,除非你用 Lisp,但是 Lisp 又有多得让人头晕目眩的圆括号。

话说回来,上面第一行 let rec 表示我们要声明一个递归函式,函式的名称为 fact,接受一个引数(Argument)记为 n。在"="之后,是函式的定义体,这是一个很简单的递归求阶乘的算法。上面第二行是 O'Caml 在收到我们的语句后,返回给我们的提示内容。它说的是,一个从 int 到 int 的函式被申明了。当然了,因为"阶乘"就是拿一个 int 来,然后算出它的阶乘,当然还是一个 int,然后返回。这里就体现出 O'Caml 的强型别系统,配上自动的型别侦测,不需要我们声明 n 和 fact 的型别,像在 C 语言中一样,O'Caml 自己就可以侦测出所有的型别关系。

下面运行一下,我们来计算 8 的阶乘。

# fact 8 ;;
- : int = 40320
#

接下来,我们来瞄一眼所谓的 Functional 编程,其妙处何在?

# let next x = x+1;;
val next : int -> int = <fun>
# let compose f g x = f(g(x));;
val compose : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b = <fun>
#

第一行,我们又定义了一个新的函式"next",它也是一个从 int 到 int 的函式,简单的加一而已。然后,我们定义了一个"复合算子",它有两个函式做引数,第三个引数我们暂且不去管它。其中,第一个函式是从型别 'a 到型别 'b,第二个函式是从型别 'c 到型别 'a。两个函式被 compose 复合后,成为一个由型别 'c 到型别 'b 的新的函式。至于 'a 和 'b 和 'c 具体到底是什么型别,我们的复合算子并不关心。这里就体现了 O'Caml 的多态(Polymorphic)的特性。这里,由 compose 的定义,我们还看到 Functional 编程可真让人惊讶,它竟然可以把一个个函式像一个个 int 或者 float 那样基本的型别一样,随意的倒来倒去。可以接受一个函式做引数,也可以返回一个函式!(我们下面紧接着就要看到返回一个函式的例子。)

接下来再看。

# let weird = compose fact next;;
val weird : int -> int = <fun>
#

这里,"compose fact next",把 fact 函式和 next 函式复合成一个新的函式,命名为 weird。这个 weird 函式是怎么一会事呢?我们看到,它当然还是一个 int 到 int 的函式。其实这个 weird 函式就是把一个 int 先加一,然后再求阶乘。也就是先 next,再 fact。读者朋友们看到这里恐怕不免有些晕乎乎的。想不到读程序也能醉人!而且是这么短的程序!我们上面看到这个 compose 不是要接收三个引数 f、g 和 x 嘛,怎么我们这里就给它两个引数,它也能返回一个结果出来?别急,别急,这也是 Functional 编程的奇妙之处,我们在下面还要详细讲到。

简单说来,如果你给 compose 三个引数,它就返回一个 int。但是,如果你给它两个引数,它就变成还要再接受一个引数,然后才能返回一个 int。请看,它还要再接收一个引数,然后才能返回,这不就变成一个函式了嘛。这个技术有个名堂,叫做"Currying",是纪念逻辑学家 Haskell Curry 的。(我的妈,逻辑学家都跑出来了!)

先往下进行,我们来看看 weird 的运算结果吧。

# weird 7;;
- : int = 40320
#

果然如此,(7+1)! = 8! = 40320。当然,你也可以一下子就给 compose 三个引数,那样的话,它一下子就返回一个 int 结果来了。

# compose fact next 7;;
- : int = 40320
#

读者朋友们如果以前只接触过 C 这一系列的编程语言的话,看到这里,恐怕会是头晕的厉害,而且不免会有疑问,这么复杂的东西,到底有什么用,有什么好处啊?Stepanov(谁是 Stepanov,STL 之父是也。何谓 STL,啊,啊,您要学的东西还比较多啊!呵呵。),他在谈到 Java 的时候说过一段有趣的话,"... for the first time in my life programming in a new language did not bring me new insights."我们反过来看,如果读者朋友您现在看 O'Caml 觉得头晕的话,这证明您正在学新的东西,而且这新的东西是如此的有趣,它能用短短的一个小程序就让您头晕!难道生活中还有比这更加有趣的事情吗?

呵呵,玩笑话放一边,我们在这一系列的文章进行到某一个阶段的时候,还是会具体的谈一谈 Functional 编程的利与弊的。不过现在我们才刚刚开始,谈这个话题还略嫌早了一些。上面说到的 STL,可以说是 C++ 中最让人心旷神怡的宝贝东东。而且,STL 也是让初学者浑身冒汗的宝贝东东。您看,即使您只在 C 系列的编程语言里面活动,也会遇到这样的事情,而且只有遇到这样的事情,才能让您的水平更上一层楼。我没说错吧?


下次再见

今天就到这里吧。下一次我们将开始介绍 Functional 编程。呵呵,美妙新世界等着我们呢!

参考资料

1 The O'Caml Language Homepage, http://www.ocaml.org

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Linux
ArticleID=20697
ArticleTitle=说一门新外语,O'Caml(之一)
publish-date=07012002