More interesting goals are created by applying a special
kind of Schelog object called a predicate (or
relation) to other
Schelog objects. Schelog comes with some primitive
predicates, such as the arithmetic operators
%=:=
and %<
,
standing for arithmetic “equal” and “less than”
respectively. For example, the following are some goals
involving these predicates:
(%which () (%=:= 1 1)) =>()true (%which () (%< 1 2)) =>()true (%which () (%=:= 1 2)) =>#f (%which () (%< 1 1)) =>#f
Other arithmetic predicates are
%>
(“greater than”),
%<=
(“less than or equal”),
%>=
(“greater than or equal”), and
%=/=
(“not equal”).
Schelog predicates are not to be confused with conventional
Scheme predicates (such as <
and =
). Schelog
predicates, when applied to arguments, produce goals
that
may either succeed or fail. Scheme predicates, when applied
to arguments, yield a boolean value. Henceforth, we will
use the term “predicate” to mean Schelog predicates.
Conventional predicates will be explicitly called “Scheme
predicates”.
Users can create their own predicates using the Schelog form
%rel
. For example, let’s
define the predicate %knows
:
(define %knows (%rel () [('Odysseus 'TeX)] [('Odysseus 'Scheme)] [('Odysseus 'Prolog)] [('Odysseus 'Penelope)] [('Penelope 'TeX)] [('Penelope 'Prolog)] [('Penelope 'Odysseus)] [('Telemachus 'TeX)] [('Telemachus 'calculus)]))
The expression has the expected meaning. Each
clause in the %rel
establishes a fact:
Odysseus
knows TeX, Telemachus knows calculus, &c. In general, if we
apply the predicate to the arguments in any one of its
clauses, we will get a successful goal. Thus, since
%knows
has a clause that reads
[('Odysseus 'TeX)]
, the goal
(%knows 'Odysseus 'TeX)
will be true.
(In the code in this text, brackets have the same behavior as parentheses. We use a mix of brackets and parentheses solely to improve the readability of the code for humans.]
We can now get answers for the following types of queries:
(%which () (%knows 'Odysseus 'TeX)) =>()true (%which () (%knows 'Telemachus 'Scheme)) =>#f
Predicates can be more complicated than the above bald recitation of facts. The predicate clauses can be rules, eg,
(define %computer-literate (%rel (person) [(person) (%knows person 'TeX) (%knows person 'Scheme)] [(person) (%knows person 'TeX) (%knows person 'Prolog)]))
This defines the predicate
%computer‑literate
in
terms of the predicate %knows
. In effect, a person is
defined as computer-literate if they know TeX and
Scheme, or TeX and Prolog.
Note that this use of
%rel
employs a local logic variable called person
.
In general, a %rel
-expression can have a list of symbols
as its second subform. These name new logic variables that
can be used within the body of the %rel
.
The following query can now be answered:
(%which () (%computer-literate 'Penelope)) =>()true
Since Penelope knows TeX and Prolog, she is computer-literate.
The above queries are yes/no questions. Logic programming allows more: We can formulate a goal with uninstantiated logic variables and then ask the querying process to provide, if possible, values for these variables that cause the goal to succeed. For instance, the query:
(%which (what) (%knows 'Odysseus what))
asks for an instantiation of the logic variable what
that satisfies the goal (%knows 'Odysseus what)
.
In other words, we are asking, “What does Odysseus know?”
Note that this use of %which
— like %rel
in the definition of %computer‑literate
—
uses a local logic
variable, what
. In general, the second subform of
%which
can be a list of local logic variables. The
%which
-query returns an answer that is a list of
bindings, one for each logic variable mentioned in its
second subform. Thus,
(%which (what) (%knows 'Odysseus what)) =>([what TeX])
But that is not all that wily Odysseus knows. Schelog
provides a zero-argument procedure (“thunk”) called
%more
that retries the goal in the last
%which
-query for a different solution.
(%more) =>([what Scheme])
We can keep pumping for more solutions:
(%more) =>([what Prolog]) (%more) =>([what Penelope]) (%more) =>#f
The final #f
shows that there are no more
solutions. This is because there are no more clauses in the
%knows
predicate that list Odysseus as knowing anything
else.
It is now clear why ()true
was the right choice for truth in
the previous yes/no %which
-queries that had no logic
variables (sec 1). %which
returns a
list of bindings
for true
goals: the list is empty when there are no variables.
For such Schemes as don’t distinguish between ()
and
#f
, we can still ask fruitful yes/no queries. Simply
use a dummy local
variable in the
%which
-expression. Truth will give an (ignorable)
binding for the dummy variable, while falsity will, as
usual, produce #f
.
(%which (bingo) (%knows 'Odysseus 'TeX)) =>([bingo _]) (%which (bingo) (%knows 'Odysseus 'calculus)) =>#f
We can add more clauses to a predicate after it has already
been defined with a %rel
. Schelog provides the
%assert
form for this purpose. Eg,
(%assert %knows () [('Odysseus 'archery)])
tacks on a new clause at the end of the existing clauses
of the %knows
predicate. Now, the query:
(%which (what) (%knows 'Odysseus what))
gives TeX, Scheme, Prolog, and Penelope, as before, but
a subsequent (%more)
yields a new result: archery
.
The Schelog form %assert‑a
is similar to %assert
but
adds clauses before any of the current clauses.
Both %assert
and %assert‑a
assume that the variable
they are adding to already names a predicate (presumably
defined using %rel
).
In order to allow defining a predicate entirely through
%assert
s, Schelog provides an empty predicate value
%empty‑rel
. %empty‑rel
takes any number of arguments
and always fails. A typical use of the
%empty‑rel
and %assert
combination:
(define %parent %empty-rel) (%assert %parent () [('Laertes 'Odysseus)]) (%assert %parent () [('Odysseus 'Telemachus)] [('Penelope 'Telemachus)])
(Schelog does not provide a predicate for retracting
assertions, since we can keep track of older versions of
predicates using conventional Scheme features (let
and set!
).)
The local logic variables of %rel
- and
%which
-expressions are in reality introduced by the
Schelog syntactic form called %let
. (%rel
and
%which
are macros written using %let
.)
%let
introduces new lexically scoped logic variables.
Supposing, instead of
(%which (what) (%knows 'Odysseus what))
we had asked
(%let (what) (%which () (%knows 'Odysseus what)))
This query, too, succeeds five times, since
Odysseus knows five things. However, %which
emits
bindings only for the local variables that it
introduces. Thus, this query emits ()true
five times before
(%more)
finally returns #f
.