Source code fro Exercise 4.60.
The definition of
and with 3 terms. Since
and is commutative –
(and a b) is equivalent to
(and b a) –
lives-near is a commutative rule –
(lives-near ?a ?b) is equivalent to
(lives-near ?b ?a). To avoid repetition of pairs, some kind of ordering of arguments is needed. I tried several methods of doing this but the only solution I found that worked was to write native racket procedures to compare lists of symbols to provide a kind of ordering for the variables used to represent people. These are then added as primitive procedures to the initial environment created in the meta-circular evaluator that the query evaluator uses to evaluate
(define (accumulate p init l) (if (null? l) init (accumulate p (p (car l)) (cdr l)))) (define (symbol-list->string p) (accumulate string-append "" (map symbol->string p))) (define (symbol-list>? person1 person2) (string>? (symbol-list->string person1) (symbol-list->string person2))) (define primitive-procedures (list (list '* *) (list '+ +) (list '- -) ... ... (list 'symbol-list->string symbol-list->string) (list 'symbol-list>? symbol-list>?) ))
For the query evaluator live-near-uniq has an additional lisp-value clause that one person is ordered before another.
(run-query '(assert! (rule (lives-near-uniq ?person-1 ?person-2) (and (address ?person-1 (?town . ?rest-1)) (address ?person-2 (?town . ?rest-2)) (not (same ?person-1 ?person-2)) (lisp-value symbol-list>? ?person-1 ?person-2))))) (run-query '(lives-near-uniq (Hacker Alyssa P) ?who)) (lives-near-uniq (Hacker Alyssa P) (Fect Cy D)) (run-query '(lives-near-uniq ?a ?b)) (lives-near-uniq (Aull DeWitt) (Bitdiddle Ben)) (lives-near-uniq (Reasoner Louis) (Aull DeWitt)) (lives-near-uniq (Reasoner Louis) (Bitdiddle Ben)) (lives-near-uniq (Hacker Alyssa P) (Fect Cy D))