Clojure与Lisp

Clifford004 8年前
   <h2>Clojure与Lisp</h2>    <p>"Lisp 不是一门语言,它是一种构建素材。" (艾伦·凯)</p>    <p>"任何C或Fortran程序复杂到一定程度之后,都会包含一个临时开发的、只有一半功能的、不完全符合规格的、到处都是bug的、运行速度很慢的Common Lisp实现。"(格林斯潘第十定律(Greenspun's Tenth Rule))</p>    <p>Clojure是一门Lisp方言(Lisp dialect).</p>    <p>Lisp 是一种编程语言,以表达性和功能强大著称,但人们通常认为它不太适合应用于一般情况。Clojure 是一种运行在 Java™ 平台上的 Lisp 方言,它的出现彻底改变了这一现状。如今,在任何具备 Java 虚拟机的地方,都可以利用 Lisp 的强大功能。</p>    <p>Clojure 是完全的,真正意义上的神圣的lisp语言的一个方言.</p>    <p>lisp语言因为其无以伦比强大能力和几乎无穷的表达力而获得了盛誉,Clojure自然也不例外. 它的功能和元编程的能力是建立在这样的基础之上的:异常驯服的C语言的"石头" 或 具有 延展性的java语言的"木头" . 你可以用几百行甚至几十行Clojure代码取替代几千行静态语言 的代码,伴随着这而来的是bug数量的减少和开发时间的缩短.</p>    <p>样板代码(Boilerplate code )被完全删去. 域指定语言(Domain Specific Languages ) 不仅 简单,而且更一般化--lisp程序往往是按照 "自下而上" 的开发方式写成的. 展开式(演进式)的 结构和语法更适合特定的问题领域. 你在程序运行的时候取修改程序,而不需要重新编译或重启 程序.</p>    <p>但是,历史上也有对lisp进行诋毁的人,或许称为抱怨更为合适. lisp发展过程中,没有完整的规范, 各种不兼容的实现,陈旧落伍的限制.cruft accumulate 在其存在的四五十年里一直存在. 对于 大多数人来说,它的语法过于诡异了.</p>    <p>Clojure 修正上面的大多数这些问题. 它保留了 lisp 的思想和哲学,并同时清除了过去的很多限制. Clojure 高速、干净、具有优先能力和优雅的特征. 但是没有改变lisp中 "代码也是数据" 的哲学. Clojure 语言在直觉和观感上比历史上的lisp更易于阅读. 在后面开始学习的初级阶段,你就发现虽然 仍有各种括号,但是代码是难以置信的容易读和写.</p>    <p>对于那些熟悉lisp语言的人来说,他们很快就会发现他们非常适应Clojure.</p>    <h2>Lisp简史</h2>    <h3>1958年,John McCarthy设计了Lisp语言</h3>    <p>20世纪50年代中期,在大多数计算机处理的都是数值数据等,包括语言学、心理学和数学领域上一些人们开始对人工智能产生了兴趣。觉得必须实现共同需要的一个方法,使计算机能够处理链表中的符号数据,允许语言的处理、信息存入和检索、定理证明的过程机器化。IBM是首先对人工智能开发有兴趣的商业机构之一。</p>    <p>1958年夏天,来自麻省理工学院的人工智能研究先驱约翰·麦卡锡(John McCarthy)参与IBM资讯研究部的工作,研究符号运算及应用需求。可是,IBM旗下的Fortran表处理语言却未能支援符号运算的递归、条件表达式、动态存储分配及隐式回收等功能。约翰·麦卡锡于1958年秋季回到麻省理工学院后,和Marvin Minsky组成了人工智能项目。开展一个表处理软件系统来实现McCarthy提出建议采纳者程序的工作,尔后推动了表处理语言LISP的诞生。</p>    <p>1960年4月,麦卡锡在ACM杂志发表了一片文章《递回函数的符号表达式以及由机器运算的方式,第一部》.</p>    <p>自1960代末年至1980年初年,各种更新LISP版本涌现,有源自加利福尼亚大学伯克利分校的Franz Lisp、在AutoCAD运行的AutoLISP前身XLISP、犹他大学开展的Standard Lisp及Portable Standard Lisp、专属于Lisp机器上运行的ZetaLisp、源自法国国家信息与自动化研究所的LeLisp、以及MIT人工智能实验室的Gerald Sussman与Guy Steele所开发的Scheme等。</p>    <p>1984年,改良自MacLisp、集各版本大成、跨平台、且被目为事实标准的Common Lisp诞生。至1994年,美国国家标准学会(ANSI)对Common Lisp语言进行了标准化。</p>    <p>自稳定运行的Common Lisp出现起,再有各机构按各自所需而开展后续Lisp,包括1990年来自欧洲用户的EuLisp、运行于Java虚拟机的Clojure、受到Maclisp影响而创的Emacs Lisp、以及自由开源来自卡内基·梅隆大学的CMUCL、还有IsLisp,Racket,ACL2等蓬勃涌现。</p>    <p>自2000年起,LISP共享者合力支援的自由开源社区逐渐形成,致力于LISP后续发展。</p>    <p>当前最新潮的编程语言,只是实现了他在1958年的设想而已。</p>    <p>这怎么可能呢?计算机技术的发展,不是日新月异吗?1958年的技术,怎么可能超过今天的水平呢?</p>    <p>这是因为John McCarthy本来没打算把Lisp设计成编程语言,至少不是我们现在意义上的编程语言。他的原意只是想做一种理论演算,用更简洁的方式定义图灵机。</p>    <p>所以,为什么上个世纪50年代的编程语言,到现在还没有过时?简单说,因为这种语言本质上不是一种技术,而是数学。数学是不会过时的。</p>    <p>Lisp语言就好比是快速排序(Quicksort)算法,这种算法是1960年提出的,至今仍然是最快的通用排序方法。</p>    <h2>Lisp的思想</h2>    <p>Lisp语言诞生的时候,就包含了9种新思想。其中一些我们今天已经习以为常,另一些则刚刚在其他高级语言中出现,至今还有2种是Lisp独有的。按照被大众接受的程度,这9种思想依次是:</p>    <h3>1 条件结构(即"if-then-else"结构)</h3>    <p>现在大家都觉得这是理所当然的,但是Fortran I就没有这个结构,它只有基于底层机器指令的goto结构。</p>    <h3>2 函数也是一种数据类型</h3>    <p>在Lisp语言中,函数与整数或字符串一样,也属于数据类型的一种。它有自己的字面表示形式(literal representation),能够储存在变量中,也能当作参数传递。一种数据类型应该有的功能,它都有。</p>    <h3>3 递归</h3>    <p>Lisp是第一种支持递归函数的高级语言。</p>    <h3>4 变量的动态类型</h3>    <p>在Lisp语言中,所有变量实际上都是指针,所指向的值有类型之分,而变量本身没有。复制变量就相当于复制指针,而不是复制它们指向的数据。</p>    <h3>5 垃圾回收机制</h3>    <h3>6 程序由表达式(expression)组成</h3>    <p>Lisp程序是一些表达式区块的集合,每个表达式都返回一个值。</p>    <h3>7 符号(symbol)类型</h3>    <p>符号实际上是一种指针,指向储存在哈希表中的字符串。</p>    <h3>8 代码使用符号和常量组成的树形表示法(notation)</h3>    <h3>9 无论什么时候,整个语言都是可用的</h3>    <p>Lisp并不真正区分读取期、编译期和运行期。你可以在读取期编译或运行代码;也可以在编译期读取或运行代码;还可以在运行期读取或者编译代码。</p>    <p>在读取期运行代码,使得用户可以重新调整(reprogram)Lisp的语法;</p>    <p>在编译期运行代码,则是Lisp宏的工作基础;</p>    <p>在运行期编译代码,使得Lisp可以在Emacs这样的程序中,充当扩展语言(extension language);</p>    <p>在运行期读取代码,使得程序之间可以用S-表达式(S-expression)通信,近来XML格式的出现使得这个概念被重新"发明"出来了。</p>    <h2>Lisp的宏</h2>    <p>Lisp语言刚出现的时候,它的思想与其他编程语言大相径庭。后者的设计思想主要由50年代后期的硬件决定。随着时间流逝,流行的编程语言不断更新换代,语言设计思想逐渐向Lisp靠拢。</p>    <p>思想1到思想5已经被广泛接受,思想6开始在主流编程语言中出现,思想7在Python语言中有所实现,不过似乎没有专用的语法。</p>    <p>思想8可能是最有意思的一点。它与思想9只是由于偶然原因,才成为Lisp语言的一部分,因为它们不属于John McCarthy的原始构想,是由他的学生Steve Russell自行添加的。它们从此使得Lisp看上去很古怪,但也成为了这种语言最独一无二的特点。</p>    <p>Lisp古怪的形式,倒不是因为它的语法很古怪,而是因为它根本没有语法,程序直接以解析树(parse tree)的形式表达出来。在其他语言中,这种形式只是经过解析在后台产生,但是Lisp直接采用它作为表达形式。它由列表构成,而列表则是Lisp的基本数据结构。</p>    <p>用一门语言自己的数据结构来表达该语言,这被证明是非常强大的功能。思想8和思想9,意味着你可以写出一种能够自己编程的程序。这可能听起来很怪异,但是对于Lisp语言却是再普通不过。最常用的做法就是使用宏。</p>    <p>术语"宏"在Lisp语言中,与其他语言中的意思不一样。Lisp宏无所不包,它既可能是某样表达式的缩略形式,也可能是一种新语言的编译器。如果你想真正地理解Lisp语言,或者想拓宽你的编程视野,那么你必须学习宏。</p>    <p>如果你创造了一种新语言,其中有car、cdr、cons、quote、cond、atom、eq这样的功能,还有一种把函数写成列表的表示方法,那么在它们的基础上,你完全可以推导出Lisp语言的所有其他部分。事实上,Lisp语言就是这样定义的,John McCarthy把语言设计成这个样子,就是为了让这种推导成为可能。</p>    <h2>Clojure简介</h2>    <p>运行于Java虚拟机的List方言Clojure.</p>    <p>Lisp是一种以表达性和功能强大著称的编程语言,但人们通常认为它不太适合应用于一般情况,而Clojure的出现彻底改变了这一现状。如今,在任何具备 Java 虚拟机的地方,都可以使用 Lisp 的强大功能。</p>    <h3>Clojure 是一种函数式编程语言</h3>    <p>它囊括了函数式编程的所有精华:</p>    <pre>  避免了不稳定状态、递归、更高阶的函数等。  </pre>    <h3>Clojure 还是一个动态类型的语言</h3>    <p>我们可以选择添加类型信息来提高代码中的关键路径的性能。</p>    <p>Clojure 不仅可在 JVM 上运行,而且可以与Java无缝融合(JVM平台的语言家族原则上都支持)的互操作性。最后,Clojure 在设计上也考虑了并发性,并具有并发编程的一些独特特性。</p>    <h3>Clojure的设计原则</h3>    <p>(1)简单: 鼓励纯函数,极简的语法(少数special form),个人也认为clojure不能算是多范式的语言(有部分OO特性),为了支持多范式引入的复杂度,我们在C++和Scala身上都看到了。</p>    <p>(2)专注:前缀运算符不需要去考虑优先级,也没有什么菱形继承的问题,动态类型系统(有利有弊),REPL提供的探索式编程方法(告别修改/编译/运行的死循环,所见即所得)。</p>    <p>(3)实用:前面提到,构建在JVM之上,跟Java语言的互操作非常容易。直接调用Java方法,不去发明一套新的调用语法,努力规避Java语言中繁琐的地方(doto,箭头宏等等)。</p>    <p>(4)清晰:纯函数(前面提到),immutable var,immutable数据结构,STM避免锁问题。不可变减少了心智的负担,降低了多线程编程的难度,纯函数也更利于测试和调试。</p>    <p>(5)一致:语法的一致性:例如doseq和for宏类似,都支持destructring,支持相同的guard语句(when,while)。数据结构的一致性:sequence抽象之上的各种高阶函数。</p>    <h2>光剑说</h2>    <p>Clojure有着独特的吸引力,首先因为它是LISP —— 一门富有传奇色彩的语言,一直希望有机会可以学习一门LISP的方言;</p>    <p>其次Clojure是一门接地气的语言,它运行在JVM这个最成功、应用最广泛平台之上,能够跟Java代码无缝互操作,JVM上所有资源都可以为Clojure所用。</p>    <p>Clojure是这样的有潜力、接地气,那么如果你要选择一门新语言来玩玩,不选它选什么?</p>    <p> </p>    <p>来自: <a href="/misc/goto?guid=4959674857996355095" rel="nofollow">https://segmentfault.com/a/1190000005824577</a></p>    <p> </p>