**Disclaimer: this page is outdated, so some code might not run. See the Tutorials page for more up to date code.**
====== cram_reasoning ======
== Overview ==
The package ''cram_reasoning'' contains a full-featured Prolog interpreter completely written in Common Lisp. In contrast to other Prolog variants it is specifically designed for programmatic use. Instead of returning one solution and waiting for user input as a Prolog shell does, the Prolog interpreter returns a lazy list of solutions that are generated on demand by accessing elements of this lazy list.
The package provides the Lisp function ''prolog'' to execute the interpreter and prove a goal. The following example demonstrates its use:
CRS> (prolog `(member ?x (a b c))
(((?X . 1)) . #S(CRAM-UTILITIES::LAZY-CONS-ELEM :GENERATOR #))
This call generates a lazy list over the solutions and the only the first solution is generated by this call. By expanding the lazy list using the function ''force-ll'', all solutions can be generated. The result looks like this:
CRS> (force-ll (prolog `(member ?x (a b c))))
(((?X . 1)) ((?X . 2)) ((?X . 3)))
As can be seen, the result is a list of sets of bindings. Each set of bindings is a list containing tuples (i.e. cons cells) with the variable name in its car and the corresponding value in its cdr. For accessing variables, the function ''var-value'' and the macro ''with-vars-bound'' are provided. The following example shows the use of ''var-value'':
CRS> (var-value '?x (lazy-car (prolog `(member ?x (a b c)))))
A
Alternatively, ''with-vars-bound'' can be used. It binds the specified variables lexically when executing the body:
CRS> (with-vars-bound (?x) (lazy-car (prolog `(member ?x (a b c))))
?x)
A
== User-defined predicates ==
The ''cram_reasoning'' package provides two ways of defining predicates. The first one is using fact-groups. The second is implementing a lisp function that gets the current bindings and the predicate's parameters and returns a list of binding sets.
=== Fact groups ===
To allow for easy re-compilation in an interactive development environments, predicates are grouped together in fact groups. When a fact-group is recompiled, it completely replaces its previous definition. That way, it is possible to define and re-define predicates interactively.
Fact groups are defined with the macro
def-fact-group name (public-predicate*) fact-definiton*
The ''public-predicate'' field is used to declare which predicates can be defined in other fact-groups as well. This is mainly for improving code robustness because the user needs to explicitly declare which predicates can be defined elsewere, too. This prevents a common error where users defined predicates at multiple locations accidentally.
Predicates are defined as ''fact-definition'' using ''<-''.
The following example shows the definition of the ''member'' predicate:
(def-fact-group member-group ()
(<- (member ?x (?x . ?_))
(<- (member ?x (?y . ?z)
(member ?x ?z))
=== Prolog Handlers ===
For easy integration with Common Lisp and for the implementation of optimized predicates, the system provides so-called Prolog handlers. A Prolog handler is a lisp function that gets the current environment (i.e. bindings) and the values of the predicate variables and returns a list of binding sets. The predicate ''format'' that is used for printing debug info on the screen can be implemented as follows:
(def-prolog-handler format (bdgs ?string &rest args)
(let ((string (var-value ?string bdgs))
(substituted-args (mapcar (lambda (arg) (var-value arg bdgs)) args)))
(declare (type string string))
(apply #'format t string args)
(list bdgs)))
Since the variables passed to the handler can be bound to variables, the actual variable values are read using ''var-value''. Then format is called and since this predicate always holds, the list of unchanged bindings is returned.
If both, a Prolog handler and fact group define a predicate, the fact group predicate is only used if the Prolog handler fails.
== Integration with Common Lisp ==
For easier integration of Common Lisp, two helper predicates are provided: ''lisp-fun'' and ''lisp-pred''. ''lisp-fun'' allows to call a lisp function and bind its result to a Prolog variable while ''lisp-pred'' can be used to use a lisp predicate function. If the predicate function returns NIL, the ''lisp-pred'' predicate will fail.
''lisp-fun'' can be used as follows:
CRS> (lazy-car (prolog `(lisp-fun symbol-value *package* ?p)))
((?P . #))
As can be seen, the result of the call to ''symbol-value'' is bound to the variable ''?p''.
The following example shows the use of ''lisp-pred'' to compare two variables using equal:
(lisp-pred equal ?a ?b)
The predicate only holds when the lisp function returns non-NIL.