2  Predicates

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”.

2.1  Predicates Introducing Facts

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

2.2  Predicates with Rules

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.

2.3  Solving Goals

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.

2.3.1  A Note on #f vs ()

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

2.4   Asserting Extra Clauses

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 %asserts, 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!).)

2.5  Local Variables

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.