10 Higher-order Predicates
Logic variables which contain predicates may be used as the operator in predicate expressions:
> (%which () (%let (p) (%and (%= p %knows) (p 'Odysseus 'TeX)))) '()
First the logic variable p is unified with the predicate %knows. In the expression
(p 'Odysseus 'TeX)
p is replaced by its value %knows to become
(%knows 'Odysseus 'TeX)
which succeeds.
This allows us to reason about predicates themselves. For example:
> (%which (p) (%member p (list %knows %parent)) (p 'Odysseus 'Penelope)) '((p . #<procedure:relation>))
> (%more) #f
Here we test which of the predicates %knows and %parent succeed when given the arguments 'Odysseus and 'Penelope.
The goal (%knows 'Odysseus 'Penelope) succeeds, but (%parent 'Odysseus 'Penelope) fails. Hence the only possible value for p is %knows.
However, logic variables used as a predicate must be instantiated. Since the set of defined predicates is not enumerable by Racklog, an unbound query will fail:
> (%which (p) (p 'Odysseus 'Penelope)) #f
We can define a higher-order predicate which tests for unary predicates that succeed with 'Odysseus as their argument:
(define (%odyssean p) (p 'Odysseus))
For example:
> (%which () (%odyssean %computer-literate)) '()
This succeeds because (%computer-literate 'Odysseus) succeeds.
> (%which () (%odyssean %compound)) #f
This fails because (%compound 'Odysseus) fails.
This also works if the predicate argument is a logic variable:
> (%which (p) (%member p (list %computer-literate %compound)) (%odyssean p)) '((p . #<procedure:%computer-literate>))
Compare this with the example above.
Racklog also provides two predicates for defining relations involving arbitrary predicates.
10.1 %apply
The %apply predicate is analogous to convential Racket apply.
The goal
(%apply P L)
succeeds if L is a list with elements E, ..., and if P is a predicate that accepts as many arguments as there are Es, and if the goal (P E ...) succeeds. For example:
> (%which () (%apply %knows '(Odysseus TeX))) '()
In this case, the goal
(%apply %knows '(Odysseus TeX))
is equivalent to
(%knows 'Odysseus 'TeX)
The list argument to %apply must be sufficiently instantiated to determine its length. The following goals succeed:
> (%which () (%apply %knows (list 'Odysseus 'TeX))) '()
> (%which (X) (%apply %knows (list X 'TeX))) '((X . Odysseus))
but it is not possible to use %apply with a list of unknown length:
> (%which (X Y) (%apply %knows (cons X Y))) #f
10.2 %andmap
The %andmap predicate is analogous to convential Racket andmap.
The goal
(%andmap P L ...+)
succeeds if all the Ls are lists of equal length, and the goal (P E ...) succeeds for each set of elements E, ... of the Ls. For example:
> (%which () (%andmap %knows '(Odysseus Penelope) '(TeX Prolog))) '()
In this case, the goal
(%andmap %knows '(Odysseus Penelope) '(TeX Prolog))
is equivalent to
(%and (%knows 'Odysseus 'TeX) (%knows 'Penelope 'Prolog))