The special forms in this section allow a Lisp expression to be evaluated, and the value used in Algernon in various ways. Before an expression is evaluated in Lisp, any Algernon variables appearing in the expression are replaced by their bindings.
Evaluates expression as a Lisp expression for side effects. Returned value is ignored. Thus one can print out the children of Tom using the path:
((child Tom ?x) (:eval (format t "A child of Tom is ~a.~%" '?x))).
Evaluates expression as a Lisp expression and succeeds iff it does not evaluate to nil.
Succeeds if variable is bound to a value (not another variable), and fails otherwise.
Succeeds if variable is unbound, and fails otherwise.
Applies function to the values obtained by evaluating exp ... exp . Each of the exp may be of one of four forms:
When :funcall appears as a top-level special form in a path, the value returned is ignored by Algernon. However, :funcall can also be embedded in :bind or :branch forms, in which case the value returned can be bound to Algernon variables.
After substituting in the values of any Algernon variables, evaluate the second argument and unify the result with the first argument. The expression may be a Lisp expression or an embedded :funcall expression. For example, to determine the number of values in a slot: (:bind ?n (:funcall #'length (:values frame slot)))
Because the variable argument is unified with the result of evaluating expression, :bind can be used to destructure and test properties of the value returned. For example, suppose the Lisp function (gossip) returns a list of the form (Tom loves Mary) or (Bill hates Joe) or some such. We could select for a particular case, and bind variables to the names of the protagonists with: (:bind (?subj loves ?obj) (gossip))
The value returned from the Lisp function is captured using multiple-value-bind, with the second argument being the set of assumptions. This means that a Lisp function could store information in an external datastructure, indexed under the appropriate assumptions, using rules something like the following:
((R ?x ?y) -> (:funcall #'Fout '?x '?y :assumptions)) ((R ?x ?y) <- (:bind ?y (:funcall #'Fin '?x :assumptions)))
(This has not been tested, and the returned values will be cached in the slot, which may not be what we want.)
:branch works just like :bind, except that the result of evaluating expression must be a list of values, and variable is unified against each of those values along a separate branch.
Since parts of these forms are evaluated by Lisp after Algernon variables are replaced by their values, and since Algernon frames are represented by Lisp symbols that are often unbound, it is important to quote variables whose bindings shouldn't be evaluated. For example, if foo is a function taking a single numerical argument, then
((:bind ?f 'foo) (:bind ?n (:funcall '?f 2))) or even
((:bind ?f 'foo) (:bind ?n (?f 2))) will work as expected, but
((:bind ?f 'foo) (:bind ?n (:funcall ?f 2))) will not.