Re: ajoo JRC

本文探讨了ajoo在JParsec项目中的贡献及其编程哲学。JParsec是一款基于Haskell的Parsec移植到Java的解析器库。文章强调了ajoo独特的编程风格和技术视野,同时分享了作者在跟随ajoo学习过程中的体会与挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ajoo牛 代码观感

刚开始接触JParsec的时候,我就对照着ajoo的calculator, mssql的等比较复杂深入的例子,向下挖掘,并随之构建一套类体系。遇到不懂的地方,就向ajoo询问。
ajoo给我的建议是从简单的步骤开始做起,这样更有信心。
我的回答是,简单的步骤并不能免除我今后应对复杂的地方。现在弄不懂的,后面还是不懂。我习惯于一开始尽量把所有障碍和难点思考清楚,提前拔除。
ajoo说,呵呵,随便你。只要你觉得能够有信心。

作大牛的跟随者,作ajoo牛的跟随者尤其难。
ajoo太敏捷了,步子迈得太快了。
讲解monad parser不久之后,JFun就问世了。JParsec,Jaskell就问世了。
几天前看他在询问和讨论Class Loader,几天后IoC container就出来了。.net版本的JParsec也是如此。
就说这个JParsec,前几天抱怨java generic is a mistake。过几天,JParsec就换上了Generic Version。前几天抱怨Groovy,过几天,Groovy的JParsec配套措施和例子就出来了。

ajoo的编程语言功底很深,一门新的working language,拿来之后,不是首先理解里面的语法特性,而是寻找其中的语法特性。因为他在此之前早已了解各种语言语法的超集,不会对什么语法特性感到惊奇,看到一门语言,首先是抱怨这个都没有,那个都没有,而不是,竟然有这个,竟然有那个。
正是因为如此,ajoo对各门新兴语言的掌握得心应手。

另一个例子是,ReadOnly。ReadOnly的特点不是掌握语言快,而是掌握应用领域框架非常快。Spring, Hibernate, WebWork,各种东西一出来,就玩的很熟。我想,这只能用头脑和经验来解释了。

ajoo牛的这种大步子,令追随者很难跟上。我遇到的主要障碍倒不是语法,咱也是当年跟着T1从SICP开始混的。主要难度在于ajoo牛的设计思路。
JParsec是一个Haskell Parser( Parsec) 的移植。我想,要想理解JParsec,从Haskell Parsec开始可能更深入一些。结果证明,这是一个错误想法。Haskell Type System的语法,尤其是Monad部分,很难理解。还是要从ajoo牛的Java代码看起,更容易一些。
不管怎么说。这个难点,不是那么容易克服的。我只好先把能够做的事情,向前推进。就是给已经搭建的简单语法结构,加上测试。果然如我所料,select from where group by having order by 这些简单语法的解析,一两个小时之内,轻松通过,毫无悬念。
正印证了我前面的说法,简单步骤,对我解决后面的复杂难点毫无帮助。我还是卡在这里了。前面看到的解决不了的难题,如果不解决,到后面遇到了,还是要解决。

那么就看JParsec的代码吧。
和ajoo讨论JRC Parser的设计过程中,发现ajoo和我的很多类似的习惯。比如,对cross/recursive/cycle reference很敏感。会尽量避免这些问题。
ajoo的代码有个特点,清晰,优雅,强悍,拙朴。怎么说呢,比如,一个use case ( such as the mssql parser),有40个类,那么其中39个类,每个类都不超过10行代码,但是剩下一个类,用来组装各个组件的那个类,可能有上千行,几千行代码。
对于ajoo来说,根本不在乎那些教条,什么面向接口编程。没有必要的情况,根本就不抽出接口。JParsec的参数和返回值都是Parser,这是一个千行大类,而不是一个接口。ajoo在乎的是,用户固定使用的亘古不变的高阶逻辑(组合子之间的关系)。换句话说,就是那些Function Name。这里面,Functional Programming的痕迹非常明显。
这种藐视一切法则,却又如此清晰优雅,又如此古拙强悍的设计,奇妙的显示在一个人的代码里面,真是惊人,惊为天人。比如,Parsers和Parser两个千行大类(Parsers有接近5000行,当然,至少一半以上,是详细的javadoc),明目张胆地进行cross reference。
看到这块地方,我心里往往有些小小得意。嘿嘿,我解耦的能力是相当强的,多年以来就是干这个的。构造的这个JRC Parser结构,虽然组合关系也是非常复杂,相互引用,但是我大量使用面向接口,IoC这类平庸的手段,把Parser组合类拆成了很多个类,每个类不超过80行。不可否认,这个设计是毫不出彩的,但是,在分解代码职责的同时,保证了代码里面没有一处cross reference。
下面说JParsec本身。初步印象是,一个大一统Context参数包含所有了所有需要交互的信息。这就是一个Continuation Passing Style。由于OO的数据构造优势,使得这类State传递的实现非常简单。以前在Haskell需要nested closure结构才能做到,在OO里面轻松用顺序结构就可以做到。
这样看来,从JParsec去理解Haskell Monad Parser对于OOer来说,是一个正确的方向。

关于单元测试。
firebody和我说,ajoo的强制单元测试做的很好。
Yes.在我看来,ajoo的 Test = Sample = Demo。每个test都很复杂,很完整,代表了一个完整的use case。
我喜欢看这样的测试。对我来说,这样更容易理解。我反而不容易理解那种一段一段的测试某个method某一部分功能的散落的测试。当然,这也很可能是我阅读代码能力不强。
java精神(基于函数式组合逻辑的javaparser框架) 一。 释名。 为什么叫精神? 如果你熟悉c++,那么你可能知道一个叫做”spirit”的parser库。它利用c++的模板元编程能力,使用c++语言本身提供了一个递归下降文法解析的框架。 我这里介绍的jparsec库,就是一个java里面的递归下降文法解析框架。 不过,它并非是spirit的java版本。 Jparsec的蓝本来自Haskell语言的parsec库。Parsec是一个基于monad的parser组合库。 这个库的目的是要在java中提供一个类似parsec, spirit的库,这种组合库并非c++的专利,java/c#也可以做到。这个库还将在java5.0上被改写,类型安全上它将也不再逊色于c++。 那么,为什么叫“函数式”呢?java是面向对象的嘛。 如果你使用过haskell, lisp等语言,这个函数式不用解释你也知道是怎么回事了。 如果你是一个老牌的c++/java程序员,那么这里还要稍微解释一下。当然如果您对这些虚头八脑的名词不感兴趣,那么,你尽可以跳过这一章,不知道什么是“函数式”,并不会影响你对这个库的理解的。 C++这几年随着gp的普及,“函数式”这个老孔乙己逐渐又被人从角落里面拽了出来。一个c++程序员所熟悉的“函数式”很可能是stl的for_each, transform,count_if这些函数。 怎么说呢,就象我不能否定str.length()这个调用属于OO一样,我也无法说for_each, transform不是函数式。 但是,“函数式”的精髓不在于此。 一般归纳起来,就像我们说OO是什么多态,封装,继承一样,“函数式”的特征被总结为: 1。无副作用。 2。高阶函数。 3。延迟计算 而最最有意义的(至少我认为如此),是基于高阶函数的函数组合能力。一些人把这叫做glue。 简短地说,什么让函数式编程如此强大?是用简单的函数组合出复杂函数的能力。 我可以想象,说到这里,你还是一头雾水。“什么是组合?1+1不是也把两个1组合成2了吗?new A(new B(), new C())不也是从B和C组合成A了?”
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值