JAVA教程之探究JVM上的LISP仓酷云
其实你不用Struts,spring这些工具,直接用jsp,servlet能够很方便地写出来,而且,可以根据个人的水平、爱好,有很多方案。而struts,spring这些工具的出来。以后Java范畴最冲动民气的事变莫过于可同意别的编程言语运转于Java假造机上。环绕JRuby、Groovy、Scala另有Rhino(JavaScript引擎)的会商已甚嚣尘上。可为何要墨守成规呢?假如你真的想跳出支流,投身于一种与Java一模一样的的言语,Lisp就不掉为一种很好的选择。如今已有几种可运转于JVM上的Lisp程序计划言语的开源完成,筹办好入手下手我们的探究之旅吧!Lisp有甚么值得研讨呢?起首,作为已有50年汗青的言语,它促进很多被我们昔日视为天经地义的看法。if-then-else布局、初期的面向对象和带渣滓接纳的主动内存办理的实验都来历于此。今朝Java程序员的热门话题——辞汇闭包(LexicalClosure),最后的探究也是七十年月在Lisp中睁开的。除此之外,Lisp还具有别的很多言语至今都未接纳的特征,这些杰出的头脑势必在将来引发中兴潮水。
本文的方针读者是成心懂得Lisp的Java开辟职员。我们将在接上去的内容中会商以后能够用在JVM上的分歧Lisp方言(dialect),令你疾速懂得Lisp程序计划事情机理和其共同的地方,文章的最初会演示怎样将Lisp代码与Java体系举行整合。
今朝存在很多可用于分歧平台的Lisp体系,有收费的也有贸易的。关于想要入手下手探究Lisp的Java用户,不分开JVM是首选,如许的话起步很简单,还能够很便利的利用一切本人熟习的Java库和相干工具。
CommonLisp和Scheme
Lisp有两种次要方言(dialect):CommonLisp和Scheme。固然计划理念大致类似,可是它们的不同仍旧充足引发孰优孰劣的剧烈争辩。
CommonLisp是1991年完成的ANSI尺度。一致了几种初期Lisp的理念,是可用于多种使用开辟的年夜型情况,其最为出名的使用是野生智能。而Scheme发生于学术界,特地举行了精简化计划,履历证是一种很好的言语,既可用于盘算机迷信教授教养,又能够作为嵌进式剧本言语。你还大概会碰到别的一些对照着名的Lisp:小型的特定于使用的DSLs,如EmacsLisp或AutoCAD的AutoLISP。
下面提到的两种次要方言(dialect)在JVM上都有响应的完成,相较而言Schemes的完成要成熟一些。ArmedBearCommonLisp(www.armedbear.org/abcl.html)十分完全的完成了CommonLisp尺度,但它存在一个成绩,假如你没有安装其余CommonList体系,就不克不及构建分发版本,这对老手多是个坚苦。
在Scheme方面,两个次要的产物是Kawa(www.gnu.org/software/kawa)和SISC(www.sisc-scheme.org——theSecondInterpreterofSchemeCode)。在这篇文章的例子傍边,我们会用到Kawa,它实践上是个框架,能制造可编译成Java字节码的新言语。Scheme只是它的完成之一。特地说一句,Kawa的创立者PerBothner今朝就任于Sun,次要处置JavaFX项目标编译器方面的事情。
别的一个值得一提的竟争敌手是Clojure(clojure.sourceforge.net)。这是一种新的言语,其Lisp方言(dialect)介于Scheme和CommonLisp之间。它是间接为JVM量身打造的,因而在下面提到的一切Lisp傍边,有着最为明晰Java整合计划。它还具有别的一些冲动民气的特征,比方内建的撑持并发和事件内存。Clojure今朝仍旧处于探究测试阶段,因而在它基本上构建程序另有些为时髦早,但它相对是一个值得存眷的项目。
读取—求值—打印—轮回
我们先来安装Kawa。它的分发版是一个独自的Jar文件,能够间接经由过程链接ftp://ftp.gnu.org/pub/gnu/kawa/kawa-1.9.1.jar下载。失掉该Jar包后,就把它加进你的类路径上,如许你就能够经由过程运转以下命令启动REPL了:
javakawa.repl#|kawa:1|#该命令启动了Kawa,并显现一个提醒符。这个中事实有何奇妙呢?REPL(READ-EVAL-PRINT-LOOP)意义是读取—求值—打印—轮回,这是与运转中的Lisp体系举行交互的体例——它“读取”你的输出,举行“求值”运算后,“打印”盘算了局,云云重复“轮回”。开辟Lisp程序的体例,与我们开辟Java程序时所遵守的“写代码、编译、运转”的周期分歧。Lisp程序员必要鼓励他们的Lisp体系,坚持它的运转形态,如许就令编译和运转时的界线含混起来。在REPL中,函数和变量在实行过程当中都是能够修正的,代码也是静态注释和编译的。
先来做点复杂的事变:把两个数字加到一同。
#|kawa:1|#(+12)3这是Lisp表达式的典范布局大概说“格局”。语法都是分歧的:表达式总被放在一对圆括号内,由于用的是前缀标记,以是“+”号要放在两个参量前。再来一个庞大点的布局,把几个格局嵌套在一同,创建一个树状布局:
#|kawa:2|#(*(+12)(-34))-3Scheme的内建函数以同种机理事情:
#|kawa:3|#(if(>(string-length"Helloworld")5)(display"Longerthan5characters"))Longerthan5characters下面程序中,用一个if语句来反省某一特定字符串的长度是不是凌驾5个字符,假如像例子中的那样反省了局为真,就会实行紧随厥后的表达式,该语句将会打印一条提醒信息。注重这里的缩进只是为了增添可读性,假如你乐意的话,能够在一行内写下一切的语句。
Lisp代码用的这类括号麋集(parenthesis-heavy)的作风也称为“S表达式(s-expressions)”。它可兼作界说布局化数据的通用办法,就像XML一样。Lisp有良多内建的函数,你能够很便利的使用S表达式格局利用数据,这类便当转而促进Lisp的别的一个壮大上风:既然语法是云云复杂,那末编写发生、修正代码的程序也要比别的言语复杂很多。当我们演示宏(macros)的例子时,会懂得到更多相似情形。
函数
Scheme一般被看作是函数式程序计划言语小家庭中的一员。与面向对象范畴分歧,Scheme笼统的次要手腕是函数和它利用的数据,而不是类和对象。在这里,你所做的每件事,实践上都是挪用一些带有参数、可以前往运转了局的函数。你能够经由过程define关头字来创立函数:
#|kawa:4|#(define(addab)(+ab))以上代码界说了一个add函数,它吸收a和b两个参数。函数体复杂地实行加法(+)盘算后主动前往实行了局。注重这里没有静态的范例声明,一切的范例反省都在运转时举行,这同别的静态言语中的体例并没有二致。
界说了下面函数后,你能够很复杂的在REPL中挪用它:
#|kawa:5|#(add12)3在Scheme的天下里,函数是一等国民,它能够像Java中的对象一样被传送,这开启了一些十分风趣的大概性。上面我们将创立一个函数,它吸收一个参数,并使它的值增添一倍:
#|kawa:6|#(define(doublea)(*a2))然后经由过程挪用list函数界说一个包括三个数字的列表:
#|kawa:7|#(definenumbers(list123))上面是最使人镇静的部分:
#|kawa:8|#(mapdoublenumbers)(246)此处挪用了带有两个参数的map函数:一个参数是个函数,别的一个参数是个列表(list)。map函数将遍历列表中的每一个元素,将其作为参数挪用所供应的函数,最初将所得了局构成一个新列表(list),正如我们在REPL中所看到的。这是能够完成Java中for轮回功效的加倍函数化的办法。
LAMBDAS
另有一个对照便利的中央在于能够使用lambda关头字界说匿名函数,这与Java匿名外部类事情机制相似。从头写下面的例程,跳过两头界说double函数那一段,map语句可写成以下情势:
#|kawa:9|#(map(lambda(a)(*2a))numbers)(246)界说仅前往lambda的函数也是有大概的,典范教科书中的例程会如许写:
#|kawa:1|#(+12)30下面的语句都做些甚么事变呢?起首界说了一个名为make-adder函数,它带有一个参数a,前往一个匿名函数,该匿名函数要吸收别的一个参数b。当挪用产生时,匿名函数管帐算a与b的和。
实行(make-adder2)——大概普通的说“给我一个函数,能够把2加到传给它的参数上”,REPL将显现一些代码,它实践上是把lambda历程作为一个字符串打印出来,要用这个函数你还能够如许写:
#|kawa:1|#(+12)31此处最为主要的事变在于lambda作为一个闭包实行。把它“封装”起来,坚持它被创立时对感化局限内变量的援用。(make-adder3)挪用后,作为前往了局的lambda保有a的值,当(add-32)实行时,它盘算3+2的值,并前往预期的5。
宏(MACROS)
到今朝为止所看到的特征都和我们在对照新的静态言语中发明的相相似,比方Ruby,它也同意你利用匿名块处置对象搜集,正如我们在后面用lambda和map函数所做的一样。以是,如今让我们来变化一下偏向,看看独属于Lisp的特征:宏(macros)。
Scheme和CommonLisp都有宏体系。人们在提到Lisp时总说它是“可编程的程序计划言语”,实在指得就是这个。有了宏,你实践上就能够和编译器创建联系关系,从头界说言语自己。此时Lisp一致的语法才真正入手下手挥功效,一切的事变都变得风趣起来。
举个复杂的例子,我们能够看一下轮回。在Scheme言语中,最后并没有界说轮回,典范的对某汇合举行迭代的体例是利用map大概递回函数挪用。多亏有一个编译器小秘诀——尾挪用优化递回(tail-calloptimizationsrecursion)——能够接纳而不用忧虑会挤爆栈。上面将先容一个十分天真的do命令并使用它来实行一个轮回,完成的程序以下:
#|kawa:1|#(+12)32下面程序中界说了一个索引变量i,初始化为0,设置依照增量1迭代增加。当表达式(=i5)的值为真时,轮回中断,前往#t(它和Java中的布尔值true相称)。在轮回里我们只是打印了一个字符串。
假如我们所必要做的只是一个复杂的轮回,下面这个例子就有良多冗余的公式化代码了。在良多情形下更可取的应该是复杂间接的完成体例:
#|kawa:1|#(+12)33多亏了宏(macros),才有大概得当地利用称为define-syntax函数,把关于dotimes的特别语法增加进言语:
#|kawa:1|#(+12)34实行上述命令能够告知体系,任何对dotimes的挪用都要被出格看待。Scheme将用我们界说的语律例则婚配一个形式,并在将了局送到编译器之前将其睁开。在这个例子中,形式是(dotimescountcommand),它被转换为尺度的do轮回。
在REPL中实行该语句,你会失掉以下了局:
#|kawa:1|#(+12)35上述例子以后一定发生两个成绩。第一,为何我们必要利用宏(macro)?用一个惯例的函数不克不及做这些事变么?谜底是“不成以”。任何对函数的挪用实践上在入手下手之前城市触发对它一切参数的求值操纵,在下面的例子中就不会产生这类情形。例如说,你如何处置(do-times0(format#t"Neverprintthis"))呢?当求值必要被提早时,只要宏(macro)才干完成这个功效。
其次,我们在宏里用了变量i,假如在command表达式中可巧有一个变量取不异的名字,这会不会发生抵触呢?这点不用忧虑,Scheme的宏以“卫生”著称。编译器会主动检测并熟知怎样处置如许的定名抵触,对程序员是完整通明的。
懂得到这些情形后,试想一下在Java中增加你本人的轮回布局,这近乎不成能。也能够说,不长短常大概,究竟编译器是开源的,以是你能够自在下载并得当利用,但这真的是一个不太实际的选择。在别的静态言语中,闭包能够给你多些自在,对言语依照本人的习气做些修改,可是仍旧存在这类情形:他们的布局并没有充足天真和壮大到可让你自在调剂语法的水平。
这类才能就是为何每当元编程言语或特定范畴言语被说起时,Lisp老是以成功者姿势呈现的缘故原由。Lisp程序员临时以来一向是彻彻底底的“自底向上编程(bottom-upprogramming)”的冠军,由于当言语自己已被调治为合适你的成绩范畴时,停滞会少量多。
在Java中挪用Scheme代码
将其余言语运转在JVM之上的一个次要优点是,不论代码用何种言语写成,都可与现存的使用举行整合。因而很简单设想,能够用Scheme来模子化一些庞大的具有易变趋向的营业逻辑,然后将它嵌进一个对照不乱的Java框架中。划定规矩引擎Jess(www.jessrules.com)是一个很好的典范,它运转于JVM之上,可是用本人的类Lisp言语来声明划定规矩。
可是让分歧的程序计划言语以一种界线明晰的体例协同事情仍是一个辣手的成绩,特别是像Java和Lisp如许存在大相径庭的言语。怎样做这类整兼并没有尺度,一切活泼在JVM上的方言都以分歧的体例处置着成绩。Kawa关于Java整合的撑持绝对较好,以是鄙人面的例子中,我们将持续用它来研讨如何用Scheme代码来界说一个SwingGUI。
在Java程序中运转Kawa代码是很复杂的:
#|kawa:1|#(+12)36在这个例子中,起首会在类路径上寻觅包括Scheme程序的叫做swing-app.scm的文件,然后创立注释程序kawa.standard.Scheme的实例,挪用它来注释文件中内容。
Kawa还不撑持在Java1.6中引进的JSR-223划定的剧本APIs(javax.scripting.ScriptEngine等),假如你必要能做这类事变的Lisp,最好的选择应当是SISC。
在Scheme中挪用Java库
在我们入手下手写年夜型Lisp程序之前,是时分找个对照符合的编纂器了,不然光是考证括号婚配的事情就够让人发狂了。最受接待的选择之一一定是Emacs,究竟它可用本人的Lisp方言举行编程,不外关于Java开辟者持续利用Eclipse大概更恬逸些。假如你是这类情形就必要在事情入手下手之前先安装一个收费的SchemeScript插件。你能够在这个网站找到它。这里另有一个称为Cusp的插件,能够用于CommonLisp的开辟。
如今,我们能够来看一下swing-app.scm的详细内容,和用Kawa界说一个复杂的GUI都必要做甚么样的事情。这个例子将会翻开一个带有按钮(button)的frame,按钮点击一次后它就会被禁用。
#|kawa:1|#(+12)37最后几行用define-namespace命令为将要用到的Java类界说缩略名,这同Java的import声明功效相似。
然后界说了frame和button,使用make函数能够创立Java对象。创立button时,我们供应一个字符串作为参数传给机关函数,Kawa能够很智能的将它翻译成必要的java.lang.String对象。
如今让我们跳过ActionListener的界说,先来看一下最初5行代码。这里的标记*:用于触发对象中的办法。比方,(*:addframebutton)的功效就同等于frame.add(button)。你要注重到Scheme独有的,能够主动将办法名从Java中的骆驼拼写作风转换为小写的以连字符分开单词。比方,set-default-close-operation将被转换为setDefaultCloseOperation。这里别的一个细节是:.可被用来会见静态域,(JFrame:.EXIT_ON_CLOSE)同等于JFrame.EXIT_ON_CLOSE。
如今往返头看一下ActionListener。这里用object函数创立了一个完成了java.awt.event.ActionListener接口的匿名类,action-performed函数被用来挪用button上的setEnabled(false)办法。此时还必要增加些信息可让编译器晓得action-performed是ActionListener接口中界说的voidactionPerformed(ActionEvente)的完成。新近我们已经说过,一般情形下在Scheme中其实不必要范例,可是此时,当与Java协同事情时,编译器就必要多晓得一些信息。
当你有了这两个文件后,编译SwingExample.java,而且确认将编译后的类和swing-app.scm文件放到类路径上,接上去便可运转javaSwingExample来看看GUI的效果。你一样也能够用load函数:(load"swing-app.scm")在REPL中实行文件中的代码,这开启了静态利用GUI构件的先河。比方,你能够经由过程在REPL中实行(*:set-textbutton"Newtext")来疾速变动button上的笔墨,并且能够当即看到修正了局失效。
固然,这个例子只是想复杂的演示怎样从Kawa中挪用Java,不管怎样它都不是你能设想中的最优良的Scheme代码。假如你的确想要在Scheme中界说一个年夜型SwingUI,那你最好提拔一点笼统级别,用一些精选的函数和宏来埋没混乱的整合代码。
资本
至心但愿我的文章能引发你对Lisp的些许乐趣。请信任我,另有大批有待探究的工具。假如想懂得更多内容能够检察以下资本:
[*]StructureandInterpretationofComputerPrograms--典范的盘算机迷信课本,是进修Scheme很好的读物(mitpress.mit.edu/sicp)
[*]PracticalCommonLisp--今朝最新、最好的CommonLisp教程(www.gigamonkeys.com/book)
[*]BeatingtheAverages--PaulGraham富有争议的论文,文中把Lisp作为创业公司的奥密兵器(www.paulgraham.com/avg.html)
[*]TheNatureofLisp--一篇经由过程对从XML和Ant到宏和特定范畴言语的剖析来注释Lisp的头脑的文章(www.defmacro.org/ramblings/lisp.html)
[*]PlanetLispandPlanetScheme--有关Lisp的blogger的站(planet.lisp.org,scheme.dk/planet)
[*]schemers.org--Scheme资本保藏站点。
[*]lisperati.com有专为Lisp计划的Logo,以一个小外星工资配角,供应自在下载利用。
关于作者
PerJacobsson是位于洛杉矶的eHarmony.com的软件架构师,使用Java已有10年汗青,近两年景为Lisp的狂酷爱好者。你能够经由过程pjacobsson.com与他获得接洽。
检察英文原文:ExploringLISPontheJVM
来自:http://www.infoq.com/cn/articles/lisp-for-jvm
其实你不用Struts,spring这些工具,直接用jsp,servlet能够很方便地写出来,而且,可以根据个人的水平、爱好,有很多方案。而struts,spring这些工具的出来。 Jive的资料在很多网站上都有,大家可以找来研究一下。相信你读完代码后,会有脱胎换骨的感觉。遗憾的是Jive从2.5以后就不再无条件的开放源代码,同时有licence限制。不过幸好还有中国一流的Java程序员关注它,外国人不开源了,中国人就不能开源吗?这里向大家推荐一个汉化的Jive版本—J道。Jive(J道版)是由中国Java界大名 鼎鼎的banq在Jive 2.1版本基础上改编而成, 全中文,增加了一些实用功能,如贴图,用户头像和用户资料查询等,而且有一个开发团队在不断升级。你可以访问banq的网站 还好,SUN提供了Javabean可以把你的JSP中的 Java代码封装起来,便于调用也便于重用。 那么我书也看了,程序也做了,别人问我的问题我都能解决了,是不是就成为高手了呢?当然没那么简单,这只是万里长征走完了第一步。不信?那你出去接一个项目,你知道怎么下手吗,你知道怎么设计吗,你知道怎么组织人员进行开发吗?你现在脑子里除了一些散乱的代码之外,可能再没有别的东西了吧! Java自面世后就非常流行,发展迅速,对C++语言形成了有力冲击。Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于个人PC、数据中心、游戏控制台 如果你学过HTML,那么事情要好办的多,如果没有,那你快去补一补HTML基础吧。其实JSP中的Java语法也不多,它更象一个脚本语言,有点象ASP。 你可以去承接一些项目做了,一开始可能有些困难,可是你有技术积累,又考虑周全,接下项目来可以迅速作完,相信大家以后都会来找你的,所以Money就哗啦啦的。。。。。。 科学超级计算机、移动电话和互联网,同时拥有全球最大的开发者专业社群。 是一种由美国SUN计算机公司(Sun Microsystems, Inc.)所研究而成的语言 Java 不同于一般的编译执行计算机语言和解释执行计算机语言。它首先将源代码编译成二进制字节码(bytecode),然后依赖各种不同平台上的虚拟机来解释执行字节码。从而实现了“一次编译、到处执行”的跨平台特性。 你一定会高兴地说,哈哈,原来成为Java高手就这么简单啊!记得Tomjava也曾碰到过一个项目经理,号称Java很简单,只要三个月就可以学会。 设计模式是高级程序员真正掌握面向对象核心思想的必修课。设计模式并不是一种具体"技术",它讲述的是思想,它不仅仅展示了接口或抽象类在实际案例中的灵活应用和智慧 Jive的资料在很多网站上都有,大家可以找来研究一下。相信你读完代码后,会有脱胎换骨的感觉。遗憾的是Jive从2.5以后就不再无条件的开放源代码,同时有licence限制。不过幸好还有中国一流的Java程序员关注它,外国人不开源了,中国人就不能开源吗?这里向大家推荐一个汉化的Jive版本—J道。Jive(J道版)是由中国Java界大名 鼎鼎的banq在Jive 2.1版本基础上改编而成, 全中文,增加了一些实用功能,如贴图,用户头像和用户资料查询等,而且有一个开发团队在不断升级。你可以访问banq的网站 至于JDBC,就不用我多说了,你如果用java编过存取数据库的程序,就应该很熟悉。还有,如果你要用Java编发送电子邮件的程序,你就得看看Javamail 了。 如果要向java web方向发展也要吧看看《Java web从入门到精通》学完再到《Struts2.0入门到精通》这样你差不多就把代码给学完了。有兴趣可以看一些设计模块和框架的包等等。 是一种使网页(Web Page)由静态(Static)转变为动态(Dynamic)的语言 象、泛型编程的特性,广泛应用于企业级Web应用开发和移动应用开发。 自从Sun推出Java以来,就力图使之无所不包,所以Java发展到现在,按应用来分主要分为三大块:J2SE,J2ME和J2EE,这也就是Sun ONE(Open Net Environment)体系。J2SE就是Java2的标准版,主要用于桌面应用软件的编程;J2ME主要应用于嵌入是系统开发,如手机和PDA的编程;J2EE是Java2的企业版,主要用于分布式的网络程序的开发,如电子商务网站和ERP系统。 还好,SUN提供了Javabean可以把你的JSP中的 Java代码封装起来,便于调用也便于重用。 Java是一种计算机编程语言,拥有跨平台、面向对java
页:
[1]