Implement 4.77

main
Felix Martin 2021-03-08 13:56:35 -05:00
parent 66726a21f8
commit f1d0c83ebc
1 changed files with 92 additions and 22 deletions

View File

@ -152,33 +152,103 @@
(eval-query '(big-shot ?x))
(newline)
(display "\nex-4.77 - improved-not\n")
(display "\nex-4.77 - improved-filter\n")
; Exercise 4.77. In section 4.4.3 we saw that not and lisp-value can cause the
; query language to give ``wrong'' answers if these filtering operations are
; applied to frames in which variables are unbound. Devise a way to fix this
; shortcoming.
; I am simply putting conjucts with unbound-variables to the end. We could do
; better by inserting the conjunct after the next conjunct that has all
; variables binded, but this implementation works well enough.
; One idea is to perform the filtering in a ``delayed'' manner by
; appending to the frame a ``promise'' to filter that is fulfilled only when
; enough variables have been bound to make the operation possible. We could
; wait to perform filtering until all other operations have been performed.
; However, for efficiency's sake, we would like to perform filtering as soon as
; possible so as to cut down on the number of intermediate frames generated.
(define (conjoin3 conjuncts frame-stream)
(if (empty-conjunction? conjuncts)
frame-stream
(let ((first (first-conjunct conjuncts))
(rest (rest-conjuncts conjuncts)))
(if (filter-with-unbound-var? first frame-stream)
(conjoin3 (append rest (list first)) frame-stream)
(conjoin3 rest (qeval first frame-stream))))))
(define (filter-with-unbound-var? operands frame-stream)
(and (or (tagged-list? operands 'not)
(tagged-list? operands 'lisp-value))
(unbound-variables? operands frame-stream)))
(define (unbound-variables? operands frame-stream)
(define (tree-walk e)
(cond ((var? e) (list e))
((pair? e) (append (tree-walk (car e))
(tree-walk (cdr e))))
(else '())))
(let ((vars (tree-walk operands))
(frame (stream-car frame-stream)))
(define (iter vars)
(cond ((null? vars) #f)
((binding-in-frame (car vars) frame) (iter (cdr vars)))
(else #t)))
(iter vars)))
(put 'and3 'qeval conjoin3)
;(eval-query
; '(and3 (supervisor ?x ?y)
; (not (job ?x (computer programmer)))))
;
;(eval-query
; '(and3 (not (job ?x (computer programmer)))
; (supervisor ?x ?y)))
(display "--")
(eval-query
'(and (supervisor ?x ?y)
(not (job ?x (computer programmer)))))
(display "\n--\n")
(display "--")
'(rule (can-replace ?p1 ?p2)
(and (or (and (job ?p1 ?j) (job ?p2 ?j))
(and (job ?p1 ?j1)
(job ?p2 ?j2)
(can-do-job ?j1 ?j2)))
(not (same ?p1 ?p2)))))
(eval-query
'(and (not (job ?x (computer programmer)))
(supervisor ?x ?y)))
(display "\n--\n")
'(and3 (lisp-value < ?s1 ?s2)
(can-replace ?p1 ?p2)
(salary ?p1 ?s1)
(salary ?p2 ?s2)))
(newline)
(display "\nex-4.78\n")
(display "\nex-4.78 - non-deterministic-query\n")
(display "\nex-4.79\n")
; Exercise 4.78. Redesign the query language as a nondeterministic program to
; be implemented using the evaluator of section 4.3, rather than as a stream
; process. In this approach, each query will produce a single answer (rather
; than the stream of all answers) and the user can type try-again to see more
; answers. You should find that much of the mechanism we built in this section
; is subsumed by nondeterministic search and backtracking. You will probably
; also find, however, that your new query language has subtle differences in
; behavior from the one implemented here. Can you find examples that illustrate
; this difference?
(display "\nex-4.79 - rule-application-environment\n")
; Exercise 4.79. When we implemented the Lisp evaluator in section 4.1, we saw
; how to use local environments to avoid name conflicts between the parameters
; of procedures. For example, in evaluating
; (define (square x)
; (* x x))
; (define (sum-of-squares x y)
; (+ (square x) (square y)))
; (sum-of-squares 3 4)
; there is no confusion between the x in square and the x in sum-of-squares,
; because we evaluate the body of each procedure in an environment that is
; specially constructed to contain bindings for the local variables. In the
; query system, we used a different strategy to avoid name conflicts in
; applying rules. Each time we apply a rule we rename the variables with new
; names that are guaranteed to be unique. The analogous strategy for the Lisp
; evaluator would be to do away with local environments and simply rename the
; variables in the body of a procedure each time we apply the procedure.
; Implement for the query language a rule-application method that uses
; environments rather than renaming. See if you can build on your environment
; structure to create constructs in the query language for dealing with large
; systems, such as the rule analog of block-structured procedures. Can you
; relate any of this to the problem of making deductions in a context (e.g.,
; ``If I supposed that P were true, then I would be able to deduce A and B.'')
; as a method of problem solving? (This problem is open-ended. A good answer is
; probably worth a Ph.D.)