6.15.'accumulate'条件元素
'accumulate'条件元素比较复杂,并难于理解,但却十分强大。可以用于对fact计数、统计fields,以及将数据存入collection等。以下将仅作简单介绍:
accumulate CE语法规则如下:
(accumulate <initializer> <action> <result> <conditional element>)在匹配中碰到accumulate CE时(特别的是:当preceding pattern匹配时,或当其所包含的CE匹配时)将产生下列事件:
1.创建一个新的执行上下文(execution context)。
2.context初始化。
3.如果该CE被LHS激活,则将包括所有从对应memory中取出的匹配标识。如果是被RHS激活,则每个匹配的LHS都会被访问到。由于每个都被访问到,因此所有与之对应的RHS也会被访问。
4.每个被考虑到的token,其所定义的变量被捆绑到执行上下文(execution context),并被执行。
5.如果当前有一个pattern正在被绑定,则结果被绑定到指定的变量。
6.最后,accumulate CE匹配圆满完成,继续下一个条件元素的匹配。
从上述事件可以看出用"accumulate"能为每个匹配执行一段相应的代码,并返回accumulated的结果。例如:下列rule对年收入超过$100,000的雇员进行计数。一个初始化为0的变量,每匹配一次就自动加一,且该变量与pattern binding绑定。
Jess> (deftemplate employee (slot salary) (slot name)) Jess> (defrule count-highly-paid-employees ?c <- (accumulate (bind ?count 0) ;; initializer (bind ?count (+ ?count 1)) ;; action ?count ;; result (employee (salary ?s&:(> ?s 100000)))) ;; CE => (printout t ?c " employees make more than $100000/year." crlf))
经过以下变换后将所有姓名存储在ArrayList中,而不是打印满足条件的雇员列表。
Jess> (defrule count-highly-paid-employees ?c <- (accumulate (bind ?list (new java.util.ArrayList)) ;; initializer (?list add ?name) ;; action ?list ;; result (employee (name ?name) (salary ?s&:(> ?s 100000)))) ;; CE => (printout t (?c toString) crlf))
注:匹配一个fact可能引起accumulate对大量的其它fact反复运算,使得计算开销过大。因此使用时需慎重。
6.16.'unique'条件元素
unique CE已被取消。该参数不会产生语法错误,但也不会执行。
6.17.节点索引hash值(node index hash value)
node index hash value是一个可调的性能参数,可设为全局参数或为每个rule单独设置。所设值越小占用内存越小,但可能以牺牲性能为代价。设置的值越大占用内存空间越大,但rule的LHS执行速度越快。
通常会为rule设置一个较大的值,由此可能会产生许多部分匹配(最好选择质数)
Jess> (defrule nihv-demo (declare (node-index-hash 169)) (item ?a) (item ?b) (item ?c) (item ?d) =>)
详细使用说明参见set-node-index-hash函数。
6.18.deftemplate中的'slot-specific'声明
和defrules一样,deftemplate的定义中可以包含一个声明(declare)部分。在此可声明许多不同属性。其中一个是"slot-specific"。一个带有这种说明的template的匹配方式也与众不同:如果由此template构造一个fact,该fact与rule的LHS相匹配并被其修正,结果取决于被修正的slot是否在pattern中被定义并用于匹配该fact。如下例:
Jess> (deftemplate D (declare (slot-specific TRUE)) (slot A) (slot B)) Jess> (defrule R ?d <- (D (A 1)) => (modify ?d (B 3)))
如果不用"slot-specific"声明,则该rule将陷入无限循环中。因为它修正了一个与LHS匹配的fact,且被修正的fact仍然匹配。通过该声明,可以只执行一次。这是许多初学者所期望的默认设置,这一现象的科学术语称之为反射(refraction)。
6.19.rule中的'no-loop'声明
如果一个rule包含声明(declare (no-loop TRUE)),则无论如何该rule不会被再次激活执行。特别是:如果一个no-loop rule与一个fact相匹配,并且该rule修改了同样的fact而该fact仍然匹配,但该rule不会再次执行,从而避免无限循环。实质上是"slot-specific"的一种加强形式。