我建议看看 Jess 和 Drools。这两个工具都实现了前向和后向链接,因此您可以看看这是如何实际实现的。
在前向链接工具中实现后向链接的一种方法是实现自动目标生成以及提供可以匹配这些目标的模式。例如,以下是用 CLIPS 编写的汽车维修程序的一些规则摘录(仅支持前向链接):
(defrule determine-engine-state ""
(not (engine-starts ?))
(not (repair ?))
=>
(assert (engine-starts (yes-or-no-p "Does the engine start (yes/no)? "))))
(defrule determine-rotation-state ""
(engine-starts no)
(not (repair ?))
=>
(assert (engine-rotates (yes-or-no-p "Does the engine rotate (yes/no)? "))))
(defrule determine-gas-level ""
(engine-starts no)
(engine-rotates yes)
(not (repair ?))
=>
(assert (tank-has-gas
(yes-or-no-p "Does the tank have any gas in it (yes/no)? "))))
(defrule tank-out-of-gas ""
(tank-has-gas no)
(not (repair ?))
=>
(assert (repair "Add gas.")))
提问规则具有条件中包含的先决条件信息,更难维护。
使用自动目标生成,可以像这样重写规则:
(defrule determine-engine-state ""
(goal (engine-starts ?))
=>
(assert (engine-starts (yes-or-no-p "Does the engine start (yes/no)? "))))
(defrule determine-rotation-state ""
(goal (engine-rotates ?))
=>
(assert (engine-rotates (yes-or-no-p "Does the engine rotate (yes/no)? "))))
(defrule determine-gas-level ""
(goal (tank-has-gas ?))
=>
(assert (tank-has-gas
(yes-or-no-p "Does the tank have any gas in it (yes/no)? "))))
(defrule tank-out-of-gas ""
(not (repair ?))
(engine-starts no)
(engine-rotates yes)
(tank-has-gas no)
=>
(assert (repair "Add gas.")))
在这种情况下,提问的规则被简化并且更容易维护。每当有针对特定类型事实的目标时,都会向用户询问其值。无需对问题的先决条件信息进行编码。自动目标生成允许油箱耗尽规则驱动包含目标的规则。如果尚未确定修复,则 (engine-starts no) 模式会在 engine-starts 事实不存在的情况下自动生成一个目标(规则引擎可以确定存在另一个匹配的规则,define-engine-state关于这个目标事实)。如果用户响应否,则 (engine-starts no) 模式将被匹配,从而为 engine-rotates 事实生成一个目标(触发确定旋转状态规则)。如果用户回答是,
使用这种目标生成方法,后向链接基本上用于获取前向链接规则所需的数据。