Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add chapter 4.4 from SICP
- Loading branch information
Showing
1 changed file
with
159 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
#lang planet neil/sicp | ||
|
||
;; ===================================== | ||
;; SICP chapter 4.4: The Query Evaluator | ||
;; ===================================== | ||
|
||
;; 4.4.4.1 The Driver Loop and Instantiation | ||
;; ----------------------------------------- | ||
|
||
(define input-prompt ";;; Query input:") | ||
(define output-prompt ";;; Query results:") | ||
|
||
(define (query-driver-loop) | ||
(prompt-for-input input-prompt) | ||
(let ((q (query-syntax-process (read)))) | ||
(cond ((assertion-to-be-added? q) | ||
(add-rule-or-assertion! (add-assertion-body q)) | ||
(newline) | ||
(display "Assertion added to data base.") | ||
(query-driver-loop)) | ||
(else | ||
(newline) | ||
(display output-prompt) | ||
(display-stream | ||
(stream-map | ||
(lambda (frame) | ||
(instantiate q | ||
frame | ||
(lambda (v f) | ||
(contract-question-mark v)))) | ||
(qeval q (singleton-stream '())))) | ||
(query-driver-loop))))) | ||
|
||
(define (instantiate exp frame unbound-var-handler) | ||
(define (copy exp) | ||
(cond ((var? exp) | ||
(let ((binding (binding-in-frame exp frame))) | ||
(if binding | ||
(copy (binding-value binding)) | ||
(unbound-var-handler exp frame)))) | ||
((pair? exp) | ||
(cons (copy (car exp)) (copy (cdr exp)))) | ||
(else exp))) | ||
(copy exp)) | ||
|
||
;; 4.4.4.2 The Evaluator | ||
;; --------------------- | ||
|
||
(define (qeval query frame-stream) | ||
(let ((qproc (get (type query) 'qeval))) | ||
(if qproc | ||
(qproc (contents query) frame-stream) | ||
(simple-query query frame-stream)))) | ||
|
||
;; * Simple queries | ||
|
||
(define (simple-query query-pattern frame-stream) | ||
(stream-flatmap | ||
(lambda (frame) | ||
(stream-append-delayed | ||
(find-assertions query-pattern frame) | ||
(delay (apply-rules query-pattern frame)))) | ||
frame-stream)) | ||
|
||
;; * Compound queries | ||
|
||
(define (conjoin conjuncts frame-stream) | ||
(if (empty-conjunction? conjuncts) | ||
frame-stream | ||
(conjoin (rest-conjuncts conjuncts) | ||
(qeval (first-conjunct conjuncts) | ||
frame-stream)))) | ||
|
||
(put 'and 'qeval conjoin) | ||
|
||
(define (disjoin disjuncts frame-stream) | ||
(if (empty-disjunction? disjuncts) | ||
the-empty-stream | ||
(interleave-delayed | ||
(qeval (first-disjunct disjuncts) frame-stream) | ||
(delay (disjoin (rest-disjuncts disjuncts) | ||
frame-stream))))) | ||
|
||
(put 'or 'qeval disjoin) | ||
|
||
;; * Filters | ||
|
||
(define (negate operands frame-stream) | ||
(stream-flatmap | ||
(lambda (frame) | ||
(if (stream-null? (qeval (negated-query operands) | ||
(singleton-stream frame))) | ||
(singleton-stream frame) | ||
the-empty-stream)) | ||
frame-stream)) | ||
|
||
(put 'not 'qeval negate) | ||
|
||
(define (lisp-value call frame-stream) | ||
(stream-flatmap | ||
(lambda (frame) | ||
(if (execute | ||
(instantiate | ||
call | ||
frame | ||
(lambda (v f) | ||
(error "Unknown pat var -- LISP-VALUE" v)))) | ||
(singleton-stream frame) | ||
the-empty-stream)) | ||
frame-stream)) | ||
|
||
(put 'lisp-value 'qeval lisp-value) | ||
|
||
(define (execute exp) | ||
(apply (eval (predicate exp) user-initial-environment) | ||
(args exp))) | ||
|
||
(define (always-true ignore frame-stream) frame-stream) | ||
|
||
(put 'always-true 'qeval always-true) | ||
|
||
;; 4.4.4.3 Finding Assertions by Pattern Matching | ||
;; ---------------------------------------------- | ||
|
||
(define (find-assertions pattern frame) | ||
(stream-flatmap (lambda (datum) | ||
(check-an-assertion datum pattern frame)) | ||
(fetch-assertions pattern frame))) | ||
|
||
(define (check-an-assertion assertion query-pat query-frame) | ||
(let ((match-result | ||
(pattern-match query-pat assertion query-frame))) | ||
(if (eq? match-result 'failed) | ||
the-empty-stream | ||
(singleton-stream match-result)))) | ||
|
||
(define (pattern-match pat dat frame) | ||
(cond ((eq? frame 'failed) 'failed) | ||
((equal? pat dat) frame) | ||
((var? pat) (extend-if-consistent pat dat frame)) | ||
((and (pair? pat) (pair? dat)) | ||
(pattern-match (cdr pat) | ||
(cdr dat) | ||
(pattern-match (car pat) | ||
(car dat) | ||
frame))) | ||
(else 'failed))) | ||
|
||
(define (extend-if-consistent var dat frame) | ||
(let ((binding (binding-in-frame var frame))) | ||
(if binding | ||
(pattern-match (binding-value binding) dat frame) | ||
(extend var dat frame)))) | ||
|
||
;; Utility functions | ||
;; ----------------- | ||
|
||
(define (prompt-for-input string) | ||
(newline) (newline) (display string) (display " ")) |