论坛首页 Java企业应用论坛

jaskell script

浏览 14943 次
锁定老帖子 主题:jaskell script
该帖已经被评为精华帖
作者 正文
   发表时间:2005-01-09  
知道这里的各位老大实践经验非常丰富, 所以希望能听取一下各位的意见,看看jaskell这个新生儿应该往哪个方向发展.

这是我在abp上贴的介绍:

用jparsec作为parser, 做了一个jaskell script interpreter。
这是一个类似haskell的在java中运行的functional scripting language. (怎么样,俺起的jaskell这个名字酷吧?)


支持高阶函数,currying,call-by-name。用来在java中处理一些动态公式计算是挺不错的。(比如说从数据库中读取公式字符串,然后计算)

这个语言是无类型的,如果运行时类型发生错误,在动态抛出异常。

注意,如果你只熟悉JAVA, 有一点区别要清楚。
java里面的函数调用是用括号,如:
f(a,b,c);
jaskell则遵循haskell的语法,函数调用没有括号,参数之间则仅仅用空格隔开。
f(a,b,c)在这个语法下表示则是: f a b c。
括号在jaskell中的唯一作用就是grouping。改变优先级,把一个表达式作为一个整体。
f a b c也就可以写成,(f a b c)或者((f a b (c))), ((f) (a) b c)等等等等。
运算符除了一个前缀负号之外,其它的都是中缀的。


因为call-by-name和无类型,可以做很多有趣的事情。比如:

定点:
fixpoint f = f (fixpoint f)
甚至lamda形式的定点:


fact 4 where
  fact' f i = if i==0 then 1 else i*f (i-1); ;
  fact = Y fact';
  Y = \h-> (\x->h (x x);); (\x->h (x x););;
  ..


这个fact 4将会返回4!,也就是24.

更有趣的是,虽然语言暂时没有提供list, switch-case的功能,用函数可以相当好地模拟:


这是模拟list的代码:
build (+); 0 1 2 3 4 5 nil where
  build f a i = if i==nil then a else build f (f a i);;
  nil = \x->x;
  ..


(+)是一个表示递加的函数。
头一个0是种子,
后面的1 2 3 4 5是这个list的内容。
nil是自定义的一个函数,用来作为结尾的标志。

因为我们是无类型的,build函数可以在输入为nil的时候返回计算结果,
而在其它的时候返回函数。

下面是有趣的switch-case的代码:

translate 3 where
  translate x = switch x
                                1 "one"
                                2 "two"
                                3 "three"
                                default "unknown"
                                nil;
  switch x v c = if v==default or x==v then return c else switch x;
  return x a= if a==nil then x else return x;
  default = \x->x;
  nil = \x->x;
  ..


switch函数用来模拟switch-case。
default这个特殊值用来标示缺省值,
return函数负责把一个值最终返回出去。


这个语言本身比较简单,但是,它可以借用java的力量,因为任何的java对象都可以被用在script内部。而script的值也可以被java程序使用。
这样,通过java语言我们可以定义一个强大的外围库给script调用。

我本来是想加入case-of的支持的,但是现在考虑到用库可以实现,大概不用加了.

haskell是个静态类型的语言.它的强大的静态类型,类型推导,泛形都非常优秀.

但是这样的牛刀对于一个脚本语言来说不免有些累赘.

而且, haskell对OO的支持有限, 即使是haskell的tuple也有些不方便.每个field的名字都是全局的, 而不象在OO语言中, 每个类有自己的名字空间.

jaskell支持了更友好的field.每个tuple拥有自己的名字空间.

另外, jaskell还支持OO风格的this变量. 这可以用来实现OO中的override的功能. 举个例子:


{val=1, use_static=val+1, use_dynamic=this.val+1}.{val=2}


头一对花括号内定义了一个tuple, 它的值是:


{val=1, use_static=2, use_dynamic=2}



第二对花括号内部表示的是field update. jaskell的field update是functional的, 也就是说, update并不改变原来tuple的值, 而只是生成一个新的tuple.

这个生成的新tuple的值是:

{val=2, use_static=2, use_dynamic=3}



这里, use_static的值没有变化, 因为我们并没有update这个field, 但是use_dynamic得值变了, 这是因为我们用了this.val, 这个this就表示延迟绑定, 实现了override.

回到定义switch-case的问题, 使用tuple, 可以定义一个更容易理解也更干净的switch-case:
translate' 2 where
  switch' x = {when a b = if x==a then return b else this, default = return}
    where
      return x = {when _ _ = this, default _ = this, eval=x} ..
    ;
  translate' x = switch' x
    .when 1 "one"
    .when 2 "two"
    .when 3 "three"
    .default "unknown"
    .eval;
  ..



这个switch'和前面的switch不同, 它使用了一个tuple, 所以不需要定义一些特殊的标识函数.

switch'有两个成员, when成员是一个函数, 它比较这个switch的值, 如果符合目标, 就调用return, 否则就返回自身. default成员也是一个函数, 它直接就调用return.

return这个函数也返回一个tuple, 它的when和default成员忽略任何参数, 直接返回自身. 它的eval成员直接返回这个值.

呵呵, 完成了tuple, 下一步应该就是在java里面实现尽量丰富的外围库了.





从某种角度说, jaskell也是一个OO语言.

你可以通过where来达到encapsulation.

比如:

{mtd1 = myfld+1, mtd2=myfld*5} where
  myfld=3
  ..


这里面, mtd1, mtd2都是public method. 但是myfld是对外部隐藏的.


你还可以通过field update来达到继承, 比如:

inherit {mtd="foo"} where
  inherit t = t.{newmtd="hello world"}
  ..


就可以通过inherit函数来达到继承的作用.

还可以通过this变量来达到重载, 这我在前面已经说明过了.

最后, OO中最基本的subsumption, 也就是说子类型可以当作父类型来用, 这在jaskell里面不是一个问题.

因为jaskell根本没有类型,

use t1 + use t2 where
    t1 = {mtd1="hello"};
    t2 = inherit t1;
    inherit t = t.{mtd1=t.mtd1+" "+mtd2, mtd2="world"};
    use t = t.mtd1;
    ..


这段代码, use函数可以用在t1身上, 也可以用在t2上.

如此, 基本的OO特征都具备了.
除此之外, 它本身还是一个函数型的语言.
等我整理一下代码和javadoc, 就可以发布到sourceforge上了.

   发表时间:2005-01-09  
强。
正好我也可以学学 函数式编程,Haskell,jparsec。:-)

google到一篇jparsec的文章。
http://www.allaboutprogram.com/blogs/index.php?skin=basic
0 请登录后投票
   发表时间:2005-01-11  
前面讲的主要是jaskell的来自母亲haskell方面的特性。下面说说来自父亲java方面的特性。

任何一个public java class都可以被import进jaskell。
这个class在jaskell代码内部被当作一个tuple使用,所有的public field, method, nested class都被当作这个tuple的一个成员。
除此之外,还有几个特殊成员,比如new用来调用构造函数,new'用来生成数组等等。

比如,在运行jaskell的时候,如果我这样写:

String source = ...;
Jaskell jaskell = new Jaskell();
  .addJavaClass(String.class);
  .addJavaClass(java.util.Date.class);;

jaskell.run(source);;


那么,在source里面的jaskell代码就可以这样做:

String.toLowerCase $ Date.toString $ Date.new "1/1/2005"

这个$函数,用来改变优先级,否则jaskell会认为String.toLowerCase Date是一个函数了。这里本来也可以用括号,
String.toLowerCase (Date.toString (Date.new "1/1/2005"););

但是有时候用$符号更简洁。

正在开发中的特性有:
1。对任何的java object, 都可以不用import class, 直接就把它当作tuple调用它的共有成员。如此, 可以不用Date.toString date,而是直接用更OO的语法date.toString。
2。throw-try-catch-finally功能。
3。foreach等命令式的控制。
4。借助动态代理,用tuple来实现java interface。
等等等等。
这些功能完成后,jaskell就可以很方便地处理java对象,和java自由交互,而不仅仅局限于函数计算和公式计算了。
0 请登录后投票
   发表时间:2005-01-19  
第一版发布。

http://sourceforge.net/project/showfiles.php?group_id=122347&package_id=141190


支持functional和OO两种风格。

所有的java对象都可以直接使用。

java函数的调用方法如下:
myobj.mymethod[1,2,"mystring"]

也就是用方括号, 而不是圆括号,来括住所有参数。

new一个对象这样调用:

java.lang.XXXClass.new[] //这个调用缺省构造。
com.mycomp.MyClass.new[a,b,c] //这个调用其它的构造函数。

支持throw, try, catch, finally.

支持synchronized。

支持用jaskell的tuple来实现java接口。

支持副作用。

回头我会写出tutorial。

昨天俺的笔记本坏了, 这两天忙着重新安装环境。(幸好老夫cvs的即时,早两天坏,我可就哭都哭不回来了)
0 请登录后投票
   发表时间:2005-01-23  
tutorial写出来了。
http://sourceforge.net/project/showfiles.php?group_id=122347&package_id=141190&release_id=297858
请大家提提意见。
0 请登录后投票
   发表时间:2005-01-25  
引用
还需要一个新的script language吗,为什么不用groovy

好。问得好!
我想类似的问题应该还有
“为什么不用python",”为什么不用ruby“等。

groovy是一个非常优秀的scripting language。我看了它的一些介绍,下面说说我的理解。

1。groovy是一个面向java developer的script语言。它的目的是给java开发者一个方便强大的扩展。它的语法非常接近java.

而jaskell是可以面向不懂编程的操作人员的。一个只要有使用excel能力的人(当然是指excel的公式计算),就应该可以使用jaskell。

jaskell的一个首要目标是,可以让这些数据录入人员,business analyst, project manager等人, 不需要去正襟危坐地学习”编程“,”面向对象“,什么”类“呀,”方法“呀之类的。她们可以直接根据企业不断变化的业务需求,输入非常接近英语的业务逻辑。

比如,数据库里面有一些虚拟数据项,这些项的值由其它的一些数据项决定。但是,这个决定的规则由business用户在日常工作中改变和维护。
此时,可以让一个不懂java的维护人员花一个小时熟悉一下jaskell的基本语法,就可以写各种不同的逻辑规则了。

如:
if north_america_sales + asian_sales > central_sales then north_america_sales - 100 else central_sales
where
north_america_sales = canada_sales+mexico_sales+united_states_sales
..


2. groovy仍然是一个命令式的面向对象的scripting language。这种命令式的语言在处理一些IO或者是效率要求较高的场合很有效。
但是,在处理一些纯粹的声明式逻辑的场合, 它没有基于函数式的语言直观。
而jaskell的core是个纯函数式的语言。没有副作用。一些如pattern match, functional update的函数式语言的功能也让它对一些特定的应用更简单。

3。我没有看到怎么在java中自定义类库给groovy使用。也许可以吧。这点我不清楚。
但是,jaskell语言保持了一个非常小的核心,大多数的功能都可以通过外围的java库来import到语言之中。

比如,jaskell连switch-case都不在语言中,而是是通过库定义的。其它的如for循环,foreach, try, catch, throw等等等等功能都是库定义的函数。

一个企业,完全可以自己用java或者jaskell定义一套符合自己业务要求的库,想多强大有多强大,然后给jaskell的使用者用就行了。


4。groovy有closure, 这可以用jaskell的lamda函数模拟。而jaskell的高阶函数,currying则不是那么容易用OO的语法模拟的。groovy的closure是一个特殊的语言元素。而jaskell中只有函数,什么都是函数,这样,语言简单很多。

5。jaskell中所有东西都是函数,而任何函数都是可以从jaskell输出到java中的。而我不清楚groovy能否把一个接受closure的函数输出到java中调用。

6。jaskell是call-by-name的,也就是lazy的。call-by-name能够产生一些非常有趣的结果,比如实现fixpoint之类的。当然,这种高级用法,普通的非程序员用户是不需要理解的。
0 请登录后投票
   发表时间:2005-02-03  
ajoo老大,偶先来批几个吧:
1. 下载的2个package不知道2者之间有何关系,不管3721,都下载下来以后,才发现jaskell package里面已经包含了jparsec的源代码,只是少了一些sample而以,应该在release notes或者package notes里面说明一下,这样偶就可以只下载想要的东东了。

2. 后缀名不对,如果是jar的话,按照惯例,应该是适用于:java -jar xxx.jar,就能够运行的这种情况,不要把jar当作zip工具来使用。

3. jar里面包含了3个jar,doc, src和test,而test已经被包含在src里面,doc也只是javadoc,如果你想独立出来,应该分成3个文件并加以说明,这样偶也能够有选择的下载了。

4. ant脚本里面用到了lib/junit.jar,但是下载的package没有这个junit lib

5. 文档不应该用mht,这个是IE专用的格式,用别的浏览器就打不开了。可以考虑使用html或者txt文件。

hehe,还没有看代码,就先说这些偶在下载,编译中遇到的不便,等看了代码再说其他东东。
0 请登录后投票
   发表时间:2005-02-03  
Readonly 写道
ajoo老大,偶先来批几个吧:
1. 下载的2个package不知道2者之间有何关系,不管3721,都下载下来以后,才发现jaskell package里面已经包含了jparsec的源代码,只是少了一些sample而以,应该在release notes或者package notes里面说明一下,这样偶就可以只下载想要的东东了。

多谢。我正在抓紧写tutorial。等tutorial写完,我会改进这个的。
Readonly 写道

2. 后缀名不对,如果是jar的话,按照惯例,应该是适用于:java -jar xxx.jar,就能够运行的这种情况,不要把jar当作zip工具来使用。

呵呵。就是觉得jar比较省事。否则用什么呢?gzip还不会使呢。

Readonly 写道

3. jar里面包含了3个jar,doc, src和test,而test已经被包含在src里面,doc也只是javadoc,如果你想独立出来,应该分成3个文件并加以说明,这样偶也能够有选择的下载了。

是有点乱。我也在考虑怎样打包最好。要是都分开,清楚是清楚,但是下载者要运行test还得把两个包都打开,好像有点麻烦。

Readonly 写道

4. ant脚本里面用到了lib/junit.jar,但是下载的package没有这个junit lib

这个。junit我可以随便加在我的包里吗?

Readonly 写道

5. 文档不应该用mht,这个是IE专用的格式,用别的浏览器就打不开了。可以考虑使用html或者txt文件。

说的对。我会改成html的。主要是不大会用word,还以为只能存成mht呢。

总之,多谢啦!
0 请登录后投票
   发表时间:2005-02-03  
spring嘟嘟 写道
感觉可以用来切换权限模型的时候,来自定义权限模型

怎么说?没大明白你的意思。
0 请登录后投票
   发表时间:2005-02-03  
ajoo 写道

呵呵。就是觉得jar比较省事。否则用什么呢?gzip还不会使呢。

改个后缀名就行了呀,jar jaskell.zip ,hehe

junit的协议是CPL,可以加入release package,不过不加也可以,这个东东相信大家都有的,在文档里面说明一下,把junit.jar需要放到lib目录下面,ant脚本才能运行test的target。

至于jaskell的package,偶觉得只要一个就够了,在文档说明一下,要看javadoc的,运行ant的某个target,测试代码才一点点,包含在里面无所谓,顶多再发布一个bin的jar。

偶贴上一个附件,就是加了2个eclipse的工程文件,可以直接导入到eclipse看代码,这样方便其他人一些。

btw,语法看起来蛮有趣的,偶看看能作什么东东玩。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics