天天看点

为什么说Tcl是最好的语言

因为最近的一个项目,粗略了解了很多适合嵌入式的小语言,PHP,Perl,Python这些已经不能算小了,Lua发展的不错但进化仍然缓慢,Squirrel和Lua很类似但采用了类C语法,另外还有很多有特色的小语言,包括Jx9,Pawn,Pike等等;语法都不古怪;Scheme或者Forth一类则更适合CS专业背景,喜欢抽象逻辑的开发者使用;当然这个列表中不能忽视Javascript,不只是因为它流行,JS从Day 1开始就是为嵌入应用设计的轻量级语言,没有太多的库依赖,语法简洁,如果不在意性能,它可以用非常小的解释器实现,例如Espruino就是基于开源项目TinyJS发展出来的,很不错。

Tcl则处在一个奇怪的位置;它现在在TIOBE的排名是100左右,基本上排在大多数程序员听说过的所有编程语言之后,但它曾经很流行,在Java出现之前;在它流行的年代,计算设备的性能很低;Unix Shell是主要的竞争对手,LISP是一个美丽的泡泡;所以Tcl从一出生开始在形式上就带有这两种语言的特点:Shell的字符串展开,LISP的表达式优先和空格分隔符;这两点可能让熟悉类C语法的大多数现代程序员都不适应;

Tcl出现的年代,GUI刚起步;在各种当时还是非常封闭的平台上写高效的GUI程序并不容易,Tk图形库一出现就受到了极大欢迎,它让程序员可以非常快速的创建简单GUI应用;时至今日,包括Python在内的很多语言,最早和缺省支持的GUI Toolkit仍然是Tk,虽然界面看起来实在土不堪言;

SUN选择了Java放弃了Tcl是对Tcl的最大打击;之后Tcl的创始人Ousterhout将Tcl和他创办的公司一起卖给了其他公司并离开了核心开发团队,这门语言开始停滞发展并迅速被其他活跃的商业语言或社区语言超越;到现在你已经基本上听不到它的名字了;

目前Tcl还在使用的一些地方包括EDA软件的内嵌语言,某些型号的Cisco的路由器脚本,自动化测试框架,等等;

说完冗长的Tcl历史之后我们回来扣这个题目,扣这个题目之前我们来看一句Tcl的实例代码,这是Tcl里自定义的一个小函数,叫K Combinator:

proc K {a b} {return $a}

proc是Tcl里声明函数(命令)的方法,K是函数名,a和b是参数变量,$a是对参数求值;所以这个命令就是你给我两个变量(或表达式),我把第一个的值还给你;一个看起来很废物的功能,right?

proc readfile filename { set f [open $filename] set data [read $f] close $f return $data}

这是一段从文件中读取数据的小程序;打开文件,读取数据,关闭文件,返回数据,不麻烦,但使用K Combinator写会更简单:

proc readfile filename { K [read [set f [open $filename]]] [close $f]}

方括号是Tcl运行其他命令的语法(调用子程序),$是把变量名转换成值;K在这里把表达式的前面部分的结果返回;一行代码完成。

或者我们该把K Combinator叫做语法糖?Maybe。

Tcl的Iconic特性是一句话:

Everything is a string, but not just a string.

任何一句Tcl语句,都是这样的格式:

commandName argument1 argument2 ... argumentN

就像Shell命令;Tcl解释器对里面的每一部分估值、展开、或替换,并最后调用command执行;参数之间使用空格分割,刚好和我们的自然语言书写习惯一样,这是巧合吗?

当然所有的计算语言差不多都这样,如果把{}块当作一个参数的话;但Tcl的不同之处在于:它的command是随便定义的,包括关键字。

IF {} THEN {} 是一个命令,while {} {}也是;事实上你可以创建任何你希望的Pattern;Tcl里有一个合并了Command(用你习惯的语言说,函数)和keyword的库,你随时可以定义新的Command替换旧的,事实上它并没有真正意义上的keyword,都是可以替换的;

它的解释器从源文件里忠实的一句一句取出代码语句,到库里去查找匹配的Pattern,然后估值、执行;

这很重要吗?是的,魔法就在这里。

我们现行的计算语言,如果时间翻过去几十年回头看,它将是一种耻辱,因为它在让人,学习计算机的思维方式,而不是相反;

曾经有一个印度诗人,因为某著名英国文人的大力推荐风靡全球;那个英国人把印度人用印度某地方言写的诗都翻译成英文,据说很美,有可能影响过徐志摩、张爱玲、和青春期的张大锤;

但事实上这个英国人出于某种不为人知的动机利用自己的文学功底对这些诗做了高度粉刷,那个印度人使用的方言,据说就只有大约2000个词汇,你能想象出一个封闭村落的原始生活里提炼出来的语言能有多大和多丰富的表现力?

在数学上,CPU的指令字,或者编程语言里的基本结构(Construct)加关键字,张开的状态空间可以是无穷的,富有变化的,和可发展的;但这是数学,不是人性,不是人类语言;

人类的语言是,我推荐你看看MIT试验心理学专家、认知科学家、语言学家Steven Pinker的很有影响力的著作:Language Instinct,语言本能;这本书告诉我们人类是如何思考的,结论性的概况是:

We Think in Pattern.

你看这篇文章,想想我们说的话,我们有语法,有主谓宾定状补结构,我们有修饰语,我们能表达What, Why, When, Where, How;而对比计算语言呢?计算语言里是if then else do while go,你两个巴掌的手指头就数得过来;

是计算语言要表达的东西不够丰富吗?不;他们表达的东西够丰富,但不是通过语言的语法结构来表达,而是通过个体程序员发明的函数名,变量名,以及编程大拿们经过工程实践总结出来的Pattern来实现,四人帮的设计模式就是代表作品;

但如果是Tcl,你可以自己去发展这门语言,你可以创建Adapter,Factory,Mediator,State Machine,Event Handler,等等等等,在语法结构层面,建立新的Construct,让这些东西就像上面的K Combinator这个小小的Trick一样,成为你创建的编程语言的一部分,直观、简洁、紧凑、流畅、自我描述,线性扩展;

这可以非常好的解释为什么一些大型软件公司仍然在积极的使用Tcl,它可以非常快速简单的把Tcl变成它独有的Domain Specific Language,让它易读易写;事实上,还在使用的Tcl版本除了很少的基础功能相同之外,每家公司都加入了很多自己需要的特性,用在不同领域的Tcl也完全不一样;它很像Linux内核的使用;

不管一个编程语言在发展之初有多么庞大的野心,注入多少商业和非商业的开发资源,最终它一定不可能面面俱到,它一定或多或少的在某些领域更擅长,在另外一些地方完全无法使用;所以仿照那句著名的谚语:一切历史都是当代史,我们可以说:

一切编程语言都是领域特定语言(Domain Specific Language);

那么当你需要定制化一门语言的时候,最好的方式并不是采用通用编程语言里最精简的语言部件去繁琐的表达你的应用,而是把这门语言直接在语法层面适应到你的要求;上帝的语言是抽象的,垂直分层的,原子有物理,分子有化学,生物有DNA;但人类的语言是线性扩张的,有丰富的语法结构,语汇,修饰方法,律师有律师的语言,会计有会计的,军人有军人的,这才是我们的语言本能;In short:

语言应该能自定义Construct,表达Pattern。

这正才是人类语言的发展方式;

说Tcl是最好的语言,当然很多人不会同意,好有很多度量方式,可能是性能,可能是功能,涵盖的范围,适合的场景;

但是如果你从语言的角度出发,而不是从编程的角度出发,Tcl提供的自定义语法结构的能力,是绝大多数其他编程语言做不到的;从这个意义上说,它抓住了语言的核心,它有潜力完成Arduino想做到的、虽然取得了长足的进步但是并没有真正完成的任务:让计算设备的行为变得真正的accessible,让编程工作更加descriptive。

当然也许不是Tcl,也许是新发展出来的其他语言,但这是正确的方向和问题的核心,年轻人,计算领域正在等着你的最后努力,让它变得更加美好,进入理想世界。

继续阅读