jess笔记_(2)

这里,将简单介绍jess的规则语言(rule language),不知道翻译得是否妥当,求指点.

   

1.语法基础:

   

1.1.空格(whitespace)

   

Jess里面出了在引号里面的空格之外,其他的和c一样,多了的少了的影响不大.因此,为了美观,

   

   

就会写成

   

   

1.2.符号(symbols)

   

jess的符号(symbols)定义和java的标识符(identifier)是差不多的.在jess里面,字母,数字,还有这些标点$ * .= + / < > _ ? #是可以作为它的合法符号.符号的开始不可以有数字,有的标点(? $ =)也是不可以作为符号的开头的,但是在一些场合(比如这里).而其他的标点就可以用在各种的符号定义开头上去.

   

jess的符号定义是大小写敏感的(case sensitive).就是说,foo,FOO,Foo,都代表着不同的符号(foo,指程序员用来代表数据,功能或命令的变量).当然,这些所谓的"符号"都是用来表达变量的,表达到意思而且容易管理就好.像下面的符号,都是合法的.

   

   

   

jess里的其他,和java比较相似.布尔变量就是TRUE和FALSE,nil则是java里的null(空).不过基于大小写敏感的尿性,TRUE是必须妥妥的大写的,而nil就要求小写.而符号crlf,表示的是换行.

   

   

1.3.jess.Value class

   

所有的jess的量,包括数字,符号,字符串等等,都可以说是一个叫jess.Value 的java类的实例(instance).当要做jess和java交互的时候就需要用上这个类.jess.Value的对象是不可变的,只要创建了出来,它的值就不可以改.你可以用type()来获取jess.Value对象所包含的数据类型.这些值会在jess.RU类(RU是Rete Utilities,Rete是一种算法,可以说是jess的核心.)中作为一系列的常量枚举出来.上面所说的符号(symbol)也是RU.ATOM中的一种类型.(atom,可以参考这里,这里有着和lisp相似的尿性,可以理解为封装在RU里面)

   

1.4.数值(numbers)

   

jess的语法分析器(parser)分别用java的语法分析功能(parsing function) java.lang.Interger.parseInt 和 java.lang.Double.parseDouble 来分析整形和浮点型数值.

   

jess有三种数值类型:RU.INTEGER(对应java的int) RU.FLOAT(对应java的double) 和RU.LONG(就像java的long) .数值的类型会在语法分析(parse)的时候被推测出来.特别注意的是,RU.LONG并不是用得很多.

   

1.5.字符串(strings)

   

jess里字符串用双引号""包围着,就像

   

   

这样的东西,很显然的字符串.

   

然而,有的东西还是和java很像的.例如:

   

   

不过,\n可是没有效果的.

   

结果是:

   

   

字符串代表着RU.STRING里面jess.Value的对象.

   

1.6.注释(comments)

   

   

注释使用;的,例如

   

   

这些就是注释``不解释``

   

   

2.结构(adding some structure)

   

显然,就这样的个体,很独立,无聊``` 正题``让他们结合起来``(put these "words" together to "sentences" in jess``)

   

2.1.Lists(列表,不知应该如何翻译,暂且不翻译)

   

jess里的基本结构就是List,用一对括号()包围起来的.一下的都是合法的lists:

   

   

   

list有点像java或者其他语言里的数组(array).在jess里list是用来把代码和数据结合起来的主要方法,一个list的概念比较广泛.只要在开头加上defrule,就可以用来定义rule.同样的方法,也可以用来定义function.

   

有的人会选择用类似java的{}的方式对付(),导致:

   

按照书上说,其实写成:

   

   

会比较符合审美… 看着办吧 呵呵``

   

只要层次分明就好,比较重要.对于有必要的时候,还是可以分开写的.因为和{}一样,()的层次清晰了对于代码的维护比较友好.

   

2.2.调用函数(calling functions)

   

如果在命令行下输入list,jess会以为你在调用函数,好比:

   

   

其中,+是函数.jess里面的是前缀表达式.当然,这些和中缀一样是可以嵌套(nested)的.例如:

   

   

关于中缀表达式可以看看这里.

   

当然,神奇的jess还不止一个函数,例如:

   

输出的函数:

   

   

   

运行clp的函数:

   

   

   

   

慎记,不可以反斜杠.否则:

   

   

还有的函数是long.我们不可以像在java那样在jess里输入一个很长的数值.这时候我们需要用long从一个字符串里创建出来.

   

   

就连给一个变量赋值都需要调用函数.bind的功能就是给变量赋值.关于变量,请看下面:

   

2.3.变量(variables)

   

jess的变量和其他的差不多,是一个由你命好名的容器,当然,容器存放的是你要的数据或者定义的数据.在其生命周期里,是允许任何类型的数值的.一个变量可以是一个简单的符号(symbol),数值(number),字符串(string),列表(list)等等.

   

许多变量在命名的前面加上?(就如上一篇的?p等等)最好在命名变量的时候不要用除了- _其他的符号.而星号*是用来定义全局变量的.也如上一篇那样,我们是不需要声明一个变量的,要用一个就写一个,比较方便.bind,就是用来联系变量和它的值,例如:

   

   

   

   

这时候,?x就定义好了:

   

   

就相当于java或者c里面的 = 那样.再如:

   

   

   

   

全局变量(global variables)

   

我们之前设的变量只要遇上jess的reset命令,都会被清除,因为reset会让rule engine的内存清空,让那些变量的存在时间变得短暂.

   

举个例子:

   

   

   

我们设定的一个全局变量?*x* 即使在reset之后,还存在,而且存在的值并不是后来bind上去的字符串,而是继续存在的一个数值3.与此同时,?n就比较悲剧,reset洗礼过后什么都没有了``

   

多字段(multifields)

一种特殊的用法,在变量前加上$ 比如$?x.可以说,变量?x和多字段$?x只是不同的命名,不过在使用上会有不同.在下文会有提及.

   

2.4.其他(more about list)

   

如果你想创建一个list但不调用函数?这就需要create$了:

   

   

这时候,grocery-list包含的就是一个有着(eggs bread milk)的list了.这种只包含数据的list叫做无格式表(plain list 不会表达,暂且这样命名)我们可以像数组那样使用.例如:

   

   

有爱的是,这里的第二个就是第二个,和数组的a[0]代表第一个有所不同.

   

关于list的还有 first$ 和 rest$

   

   

   

   

$first指的是把一个pliant list 的第一项显示出来,而rest$则是列出第二项开始的后面所有的元素.

   

更有爱的是,list是可以连在一起的.添加的方式很方便.例如:

   

   

这里新建了一个list,把之前的那个?grocery-list也连在一起了.

   

当然,自我添加的方式:

   

这时候,之前的more-groceries的值是不变的.

   

最后,有一个类似第几个的访问方式:nth$

   

   

   

   

   

   

3.流控制(control flow)

   

有了list的存在,我们就应该对之有所操作.例如:

   

apply , build , eval , foreach , if/then/else , progn , while

   

由最常用的开始说起:

   

3.1.foreach

   

foreach会对一个plain list的每个元素进行你所要的设定,操作等.大致的格式如下:

   

(foreach <variable> <list> <expression>+)

   

expression 可以理解为你要对之的操作. 当然,expression也不是就只有一个操作.举个简单例子,例如:

   

   

创建完毕grocery-list之后,对每一个元素都进行自身加上换行的输出.

   

foreach可以对一个list进行方便的操作,例如创建等等.用foreach可以比较方便地定义循环.不过,更通用的会是while.

   

3.2.while

   

while不解释,和很多都类似的.大致格式如下:

   

(while <Boolean expression> do <expression>+)

   

一般说来就是条件为真时候做到条件为假.例如:

   

   

   

如果wile的条件总是真的话,是停不了的…

   

(当然 还在增加,到溢出还在工作….)

   

下一个,到if/then/else

   

3.3.if/then/else

   

当然,也不解释,毕竟比较熟悉的用法.语法声明大概如下:

   

(if <Boolean expression> then <expression>+ [else <expression>+])

   

和刚才的一样,不过就只走一圈.用来判断.

举个例子:函数menber$ 可以发现plain list里是否有该元素,有就返回TRUE,否则返回FALSE.例如:

   

   

当然,和java或者c之类的一样,是可嵌套(nested)的:

   

   

   

在命令行的jess下如果没有输入完而且代码比较长的时候 不要按 方向键↑ 要不是的话 会都没有的…

   

下一个,到类似for的东西,不过 这里是progn

   

3.4.progn

   

大概的格式如下:

   

(progn <expression>+)

   

只会反映出当下的布尔值,但是如果是类似循环的判断,就比较类似for了,和while结合起来的时候.例如:

   

   

   

当然,可以由下面的方法改写:

   

   

   

progn更多的在模式匹配(pattern matching)里会用上,因此还是有需要的.

   

下面的比较好玩,不过不常用:apply

   

3.5.apply

   

这个时候,我们可以像发号命令一样用.大致格式如下:

   

(apply <function-name> <expression>+)

   

例如对几个数,1 2 3 , 我们可以+,也可以-.这时候用apply就可以用:

   

   

   

3.6.eval and build

   

用法都是把jess数据变成代码.他们的对象都是完整的jess表达式.而且带有学习(learn)的功能.

   

eval和build用法是差不多的,不过因为历史原因,eval用在

解析string并且返回结果(在基于字符串的函数调用的多).而build则用在规则的集合上.

   

eval的例子:

   

   

   

4.用deffunction定义函数

   

格式大致如下:

   

(deffunction <name> (<parameter>*) [<comment>] <expression>*)

   

deffunction的名字(name)必须是一个符号(symbol),每个参数(parameter)必须是变量名(variable name).

   

注释(comment)不是必要的,用"双引号"引起来说明函数的功能.最好可以简洁地写上注释.至于expression,核心部分,你懂得.

   

在jess in action里面是这样描述一个场景的:很好,伟大的我们现在在意见游戏公司里面上班,然后经营的搏斗游戏需要计算出两个物体之间的距离,为了不用做重复输入那样的屌丝行为….

   

这个函数就不解释了.只写在jess里面的用法:

   

   

现在,到了多字段(multifields)的环节,用来求最小值.

说白了,就是每一个上面都搜索一次,然后取最小的返回.

   

   

   

   

5.调整程序的行为(fine-turning a function's behavior)

   

正如上面说,nth$是由1开始算起的,和很多的不同,由0算起.但是,如果不习惯的话,还是可以调整的.用的是defadvice:(大概就是把他们都往前挪一位 开个新的list)

   

   

   

   

解除的方法,就是undefadvice

   

   

   

   

   

   

   

   

   

posted @ 2012-12-12 21:12  方包  阅读(1344)  评论(2编辑  收藏  举报