exists不能和test CE合成在同一pattern中。
注意:exists正好相当于(事实上是实现了)两个嵌套的not CE;例:
(exists (A)) 相当于(not (not (A)))。人们经常写类似于(not (exists (A)))的语句,实际上相当于(not (A))。
6.12. The 'test' conditional element.
以test为首的pattern较为特殊,body不是通过使用所含的pattern而是用布尔函数与working memory相匹配。计算该函数的结果决定该pattern是否匹配。一个test pattern不匹配当且仅当计算所得函数值为FALSE;如果计算所得函数值为TRUE或其他任何值,pattern均匹配。例:
Jess> (deftemplate person (slot age)) Jess> (defrule example-8 (test (eq 4 (+ 2 2))) => (printout t "2 + 2 is 4!" crlf))
注意:test pattern和not一样,不能包含任何事先未帮定到pattern的变量。test和not可以相互组合:
(not (test (eq ?X 3)))等价于(test (neq ?X 3))
每当rule的LHS之前的(preceding)pattern计算过后,test CE也要计算一下。因此以下两个rule在执行时是完全等价:
Jess> (defrule rule_1 (foo ?X) (test (> ?X 3)) =>) Jess> (defrule rule_2 (foo ?X&:(> ?X 3)) =>)
当test CE作为rule的LHS的第一个pattern或在一个or CE的某分支中作为第一个pattern时,该pattern(initial-fact)被插入并作为test的前继(preceding) pattern。因此该fact(initial-fact)对于test条件元素的本征函数(proper functioning)来说也很重要。
6.12.1.不同时间方法的返回值(time-varying method returns)
test CE的一个有用的属性是:rule的结果可能在slot的内容都没有变化时改变,此时test CE是唯一有效的可以嵌入test的地方。例:假设有两个Java类A和B,并且A有一个方法contains,该方法将B作为一个自变量返回一个布尔值。进一步假设对于任何给定的B对象,contains的返回值会随之改变。最后假设为这两个类分别定义了一个shadow fact template,并且为其编写相应的rule。在上述条件下,下列pattern:
(A (OBJECT ?a))
(B (OBJECT ?b&:(?a contains ?b)))
是错误的。如果contains的返回值改变时,该匹配将会失效,同时Jess的内部数据结构可能会被破坏。值得注意的是,这种构造方式会导致内存溢出。
正确的表述上述pattern需要用到test条件元素,如下:
(A (OBJECT ?a))
(B (OBJECT ?b))
(test (?a contains ?b))
已保证在每次target和自变量相结合时,函数contains最多被调用一次影响。这样返回值的任何变化都不会产生负面影响。
6.12.2.何时使用test
事实上test被过度使用了,使用test通常效率没有在前一个pattern中添加同样的test到slot中高。千万不要效仿以下做法:
Jess> (defrule bad-test-usage (foo ?x) (test (< ?x 3)) =>)
相反,正确的做法如下:
Jess> (defrule better (foo ?x&:(< ?x 3)) =>)
仅当没有preceding pattern时使用test,或者如前所述当返回值随时间变化时。
6.13.'logical'条件元素
logical可用于指定fact间的逻辑依赖(logical dependencies)。在一个rule的RHS中定义的所有的fact取决于rule的LHS中的logical pattern是否匹配。如果其中任何一个匹配失效,则这些dependent fact自动失效。例:构造一个简单的fact使之依赖于(depend on)另一个简单的fact:
Jess> (defrule rule-1 (logical (faucet-open)) => (assert (water-flowing))) TRUE Jess> (assert (faucet-open)) <Fact-0> Jess> (run) 1 Jess> (facts) f-0 (MAIN::faucet-open) f-1 (MAIN::water-flowing) For a total of 2 facts in module MAIN. Jess> (watch facts) TRUE Jess> (retract (fact-id 0)) <== f-0 (MAIN::faucet-open) <== f-1 (MAIN::water-flowing) TRUE
其中(water-flowing)fact在逻辑上依赖于(faucet-open)fact,所以当后者被撤销时前者也被取消了。
fact可以从多个源得到逻辑前提——特别的:fact有可能被声明了多次且每次都有一组不同的逻辑前提。这样的fact不能自动撤销,除非它的每一个逻辑前提都被取消了。
如果一个fact的声明没有外在(explicit)的逻辑前提,则被认为是无前提条件的(unconditionally supported)。如果一个无前提条件的fact也接受explicit logical support,则取消这些前提(support)不会导致fact的撤销。
如果一个或一个以上的logical CE出现在rule中,则它们必须集中于rule的所有pattern的最前面。在一个rule中,logical CE之前不能有任何其他类型的CE。
在logical CE下,shadow fact与其他fact是一样的。shadow fact可以提供逻辑前提也可以接受逻辑前提。在当前执行中,shadow fact只能提供作为一个整体的逻辑前提。在未来的Jess版本中,一个shadow fact有可能可以提供基于各个slot值的逻辑前提。
Jess语言函数dpendents和dependencies可以提供在fact之间查询逻辑依赖的功能。
6.14.'forall'条件元素
当其中每个匹配的第一个pattern时匹配forall grouping CE,其subsequent patterns也均匹配。例:
Jess> (defrule every-employee-has-a-stapler-and-holepunch (forall (employee (name ?n)) (stapler (owner ?n)) (holepunch (owner ?n))) => (printout t "Every employee has a stapler and a holepunch." crlf)
当所有100名雇员都满足上述两个条件时,该rule被执行(fire)。如果其中有一个雇员不满足条件,则该rule就不会执行。