Meta-rules can also be used to provide an explanation facility. A full implementation of the explanation facility described here is included among the examples distributed with KnowledgeWorks, and is given also in Explanation Facility
Suppose we have a rule about truck scheduling of the form
(defrule allocate-truck-to-load :forward
(load ?l size ?s truck nil destination
?d location ?loc)
(test (not (eq ?d ?loc)))
(truck ?t capacity ?c load nil location ?loc)
(test (> ?c ?s))
-->
(assert (truck ?t load ?l))
(assert (load ?l truck ?t)))
and we wish to add an explanation by entering a form like
(defexplain allocate-truck-to-load
:why ("~S has not reached its destination
~S and ~ does not have a truck
allocated, ~ ~S does not have a load
allocated, and ~ with capacity ~S is
able to carry the load, ~ and both
are at the same place ~S"
?l ?d ?t ?c ?loc)
:what ("~S is scheduled to carry ~S to ~S"
?t ?l ?d)
:because ("A customer requires ~S to be
moved to ~S" ?l ?d))
where the :why
form explains why the rule is allowed to fire, the :what
form explains what the rule does and the :because
gives the ultimate reason for firing the rule.
The stages in the implementation are as follows:
defexplain
to store the explanation information in, say, a hash-table keyed against the rule name add-explanation
takes an instantiation, fetches the explanation information from the hash-table and the variable bindings in the instantiation, and adds the generated explanations to another global data structure, something like:(defun add-instantiation (inst)
(let ((explain-info
(gethash (inst-rulename inst)
*explain-table*)))
(when explain-info
(do-the-rest explain-info
(inst-bindings inst))))))
(defrule explain-context :backward
((explain-context)
<--
(start-cycle)
(instantiation ?inst)
((add-explanation ?inst))
(fire-rule ?inst)
(cut)
(explain-context)))