Jess notes 6 自定义规则 (4)

6.20.前向链接和后向链接(forward and backward chaining)

目前为止所介绍的都是前向forward-chaining rule,其基本含义是rule被视为类似if...then的表述。engine被动的执行位于RHS的被激发的rule。一些基于rule的系统,像著名的Prolog语言及其派生语言,都支持backward chaining。在backward chaining系统中,rule仍然以if...then的表述形式,但engine会设法激活那些前提条件(precondition)并不满足的rule。这种做出称为"goal seeking"Jess同时支持forwardbackward chaining。注意:在这里简化了Jess中关于backward chaining的描述,详见underlying algorithms一节。

 

使用Jess中的backward chaining时,必须先声明那些fact将被backward chaining重复激发。可以在定义template时做这一声明:

Jess> (deftemplate factorial
	(declare (ordered TRUE)
	(backchain-reactive TRUE))

 

同样也可以在定义template后使用do-backward-chaining函数:

Jess> (do-backward-chaining factorial)

 

然后可以定义匹配这样的patternrule。注意:必须在定义其他使用templaterule之前将该templatebackward chaining reactive相关联。

Jess> (defrule print-factorial-10
	(factorial 10 ?r1)
	=>
	(printout t "The factorial of 10 is " ?r1 crlf))

 

rule编译器发现一个pattern与一个backward chaining reactive template相匹配时,就重写rule并向ruleLHS的内部表述中插入一些特定代码。这些代码添加一个类似下面的factfact-list中:

(need-factorial 10 nil)

rule引擎重启时,没有该pattern的匹配。fact包括重新激活的pattern的头部,并以"need-"作为前缀。

 

现在可以编写与这些need-(x) fact相匹配的rule了:

Jess> (defrule do-factorial
	(need-factorial ?x ?)
	=>
	(bind ?r 1)
	(bind ?n ?x)
	(while (> ?n 1)
	(bind ?r (* ?r ?n))
	(bind ?n (- ?n 1)))
	(assert (factorial ?x ?r)))

 

rule编译器也按如下方式重写rule:为该factorial(阶乘) patternruleLHS添加一个不匹配的值。

 

最终可以编写出符合各种要求(如阶乘)的rule,当由于缺少一个(factorialfact而不能fire时,任何(need-factorialrule都可能被激发。如果这些rule开始fire了,则所需的fact会出现,并执行(fire)。由此形成backward chainJess将反向链接所有reactive pattern。如:

Jess> (do-backward-chaining foo)
TRUE
Jess> (do-backward-chaining bar)
TRUE
Jess> (defrule rule-1
	(foo ?A ?B)
	=>
	(printout t foo crlf))
TRUE
Jess> (defrule create-foo
	(need-foo $?)
	(bar ?X ?Y)
	=>
	(assert (foo A B)))
TRUE
Jess> (defrule create-bar
	(need-bar $?)
	42
	=>
	(assert (bar C D)))
TRUE
Jess> (reset)
TRUE
Jess> (run)
foo
3

 

在上例中,一开始没有一条rule被激发。Jess发现当有一个合适的foo fact时,rule-1可以被激发,于是就生成一个(need-foo nil nil)请求。这样可以匹配(由于缺少一个bar fact而不能激发的)create-foo ruleLHS中的一部分。因此Jess又生成一个(need-bar nil nil)请求。由此匹配create-barLHS,该rule执行(fire)asserts (bar C D)。随后激发并firecreate-foo,并asserts (foo A B)。最终导致激发并firerule-1

 

有一个特殊的条件元素(explicit),通过它可以环绕约束pattern在反向时不会逆转。

 

6.21.Defmodules

一个典型的基于rule的系统可以随意的包含上百条rule,而一个大型的系统甚至可以包含上千条rule。开发如此复杂的一个系统可能是一项比较艰巨的任务,同时使这些rule之间的交互更为困难。

 

这也许会让你想到要将rule分割为易于管理的整块来解决这一难题。Module的作用就是将ruletemplate分割为独立的组群。拥有列出结构的命令可以指定模块(module)的名称,

 

同时可以一次一个的对模块进行操作。如果没有明确指定一个模块,这些命令(以及其它命

 

令)默认情况下作用在当前的模块上。如果没有明确的定义任何模块,则当前的模块总是被命名为主模块(main module),即MAIN。目前为止所介绍的所有的结构都定义在MAIN中,因此在Jess中显示时常以"MAIN::"作为开头。

 

除了能帮助管理数量巨大的rule以外,模块还能提款一种控制机制:仅当模块被选中时,该模块中的rule才会fire,并且同一时间内只能选中一个模块。

 

CLIPS用户请注意:Jessdefmodule结构类似于CLIPS中的一个同名结构,但并不完全一样。

 

Jess的语法和名称定义机制比CLIPS简单。两者focus机制基本一致。

 

6.21.1.模块中的结构定义

可以使用defmodule结构定义一个新的模块:

Jess> (defmodule WORK)
TRUE

 

通过在定义时指定模块名,可以在模块中插入deftemplate,defruledeffact等结构:

Jess> (deftemplate WORK::job (slot salary))
TRUE
Jess> (list-deftemplates WORK)
WORK::job
For a total of 1 deftemplates in module WORK.

 

一旦定义完一个模块后,该模块就成为当前模块:

Jess> (get-current-module)
MAIN
Jess> (defmodule COMMUTE)
TRUE
Jess> (get-current-module)
COMMUTE

 

如果没有指定模块,则所有定义的deffact,templaterule将自动加入当前的模块:

Jess> (deftemplate bus (slot route-number))
TRUE
Jess> (defrule take-the-bus
	?bus <- (bus (route-number 76))
	(have-correct-change)
	=>
	(get-on ?bus))
TRUE
Jess> (ppdefrule take-the-bus)
	"(defrule COMMUTE::take-the-bus
	?bus <- (bus (route-number 76))
	(have-correct-change)
	=>
	(get-on ?bus))"

 

可以通过使用set-current-module函数来改变当前模块并指定其他模块。在commute模型中隐含了have-correct-change模板,因为所有的rule的定义都在其中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值