aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Comeaux <jacquesrcomeaux@protonmail.com>2023-11-25 23:57:52 -0600
committerJacques Comeaux <jacquesrcomeaux@protonmail.com>2023-11-25 23:57:52 -0600
commitd49168d930b6b5a68c6ad582639efae6b9735796 (patch)
tree68c85f59dd6a85feeadd4a77cad999c94f5b4727
parente49ddf65a17c51e64b7bac9e9e312828e9424a0f (diff)
Begin chapter 4 part 4
-rw-r--r--chap4/part4.rkt748
1 files changed, 748 insertions, 0 deletions
diff --git a/chap4/part4.rkt b/chap4/part4.rkt
new file mode 100644
index 0000000..779437e
--- /dev/null
+++ b/chap4/part4.rkt
@@ -0,0 +1,748 @@
+#lang sicp
+(#%require (only racket/base print-as-expression print-mpair-curly-braces make-base-namespace))
+(print-as-expression #f)
+(print-mpair-curly-braces #f)
+
+;; Chapter 4
+;; Metalinguistic Abstraction
+
+;; 4.4
+;; Logic Programming
+
+;; Deductive Information Retrieval
+
+(#%provide personel-defs)
+(define personel-defs
+ '((address (Bitdiddle Ben) (Slumerville (Ridge Road) 10))
+ (job (Bitdiddle Ben) (computer wizard))
+ (salary (Bitdiddle Ben) 60000)
+ (supervisor (Bitdiddle Ben) (Warbucks Oliver))
+
+ (address (Hacker Alyssa P) (Cambridge (Mass Ave) 78))
+ (job (Hacker Alyssa P) (computer programmer))
+ (salary (Hacker Alyssa P) 40000)
+ (supervisor (Hacker Alyssa P) (Bitdiddle Ben))
+
+ (address (Fect Cy D) (Cambridge (Ames Street) 3))
+ (job (Fect Cy D) (computer programmer))
+ (salary (Fect Cy D) 35000)
+ (supervisor (Fect Cy D) (Bitdiddle Ben))
+
+ (address (Tweakit Lem E) (Boston (Bay State Road) 22))
+ (job (Tweakit Lem E) (computer technician))
+ (salary (Tweakit Lem E) 25000)
+ (supervisor (Tweakit Lem E) (Bitdiddle Ben))
+
+ (address (Reasoner Louis) (Slumerville (Pine Tree Road) 80))
+ (job (Reasoner Louis) (computer programmer trainee))
+ (salary (Reasoner Louis) 30000)
+ (supervisor (Reasoner Louis) (Hacker Alyssa P))
+
+ (address (Warbucks Oliver) (Swellesly (Top Heap Road)))
+ (job (Warbucks Oliver) (administration big wheel))
+ (salary (Warbucks Oliver) 150000)
+
+ (address (Scrooge Eben) (Weston (Shady Lane) 10))
+ (job (Scrooge Eben) (accounting chief accountant))
+ (salary (Scrooge Eben) 75000)
+ (supervisor (Scrooge Eben) (Warbucks Oliver))
+
+ (address (Cratchet Robert) (Allston (N Harvard Street) 16))
+ (job (Cratchet Robert) (accounting scrivener))
+ (salary (Cratchet Robert) 18000)
+ (supervisor (Cratchet Robert) (Scrooge Eben))
+
+ (address (Aull DeWitt) (Slumerville (Onion Square) 5))
+ (job (Aull DeWitt) (administration secretary))
+ (salary (Aull DeWitt) 25000)
+ (supervisor (Aull DeWitt) (Warbucks Oliver))
+
+ (can-do-job (computer wizard) (computer programmer))
+ (can-do-job (computer wizard) (computer technician))
+ (can-do-job (computer programmer) (computer trainee))
+ (can-do-job (administration secretary) (administration big wheel))
+
+ ))
+
+(define example-queries
+ '((job ?x (computer programmer))
+ (address ?x ?y)
+ (supervisor ?x ?x)
+ (job ?x (computer ?type))
+ (job ?x (computer . ?type))
+ ))
+
+#| 4.55 |#
+
+(define simple-queries
+ '((supervisor ?x (Bitdiddle Ben))
+ (job ?x (accounting . ?type))
+ (address ?x (Slumerville . ?addr))))
+
+#| 4.56 |#
+
+(define compund-queries
+ '((and
+ (supervisor ?person (Bitdiddle Ben))
+ (address ?person ?where))
+ (and
+ (salary (Bitdiddle Ben) ?ben-salary)
+ (salary ?person ?amount)
+ (lisp-value < ?amount ?ben-salary))
+ (and
+ (supervisor ?name ?sup)
+ (not (job ?sup (computer . ?type))))))
+
+(#%provide rule-defs)
+(define rule-defs
+ '((rule (lives-near ?person-1 ?person-2)
+ (and
+ (address ?person-1 (?town . ?rest-1))
+ (address ?person-2 (?town . ?rest-2))
+ (not (same ?person-1 ?person-2))))
+ (rule (same ?x ?x))
+ (rule (wheel ?person)
+ (and
+ (supervisor ?middle-manager ?person)
+ (supervisor ?x ?middle-manager)))
+ (rule (outranked-by ?staff-person ?boss)
+ (or
+ (supervisor ?staff-person ?boss)
+ (and
+ (supervisor ?staff-person ?middle-manager)
+ (outranked-by ?middle-manager ?boss))))))
+
+(define (make-assertion x) (list 'assert! x))
+
+(#%provide q-defs)
+(define q-defs
+ (map
+ make-assertion
+ (append personel-defs rule-defs)))
+
+#| 4.57 |#
+
+(define can-replace-def
+ '(rule (can-replace ?p1 ?p2)
+ (and
+ (job ?p1 ?p1-job)
+ (job ?p2 ?p2-job)
+ (or
+ (same ?p1-job ?p2-job)
+ (can-do-job ?p1-job ?p2-job))
+ (not (same ?p1 ?p2)))))
+
+(define can-replace-example-1
+ '(can-replace ?x (Fect Cy D)))
+
+(define can-replace-example-2
+ '(and
+ (can-replace ?x ?y)
+ (salary ?x ?x-salary)
+ (salary ?y ?y-salary)
+ (lisp-value < ?x-salary ?y-salary)))
+
+#| 4.58 |#
+
+(define big-shot-def
+ '(rule (big-shot ?x)
+ (and
+ (job ?x (?div . ?rest))
+ (not
+ (and
+ (supervisor ?x ?sup)
+ (job ?sup (?div . ?rest-2))))))
+
+#| 4.59 |#
+
+(define meeting-defs
+ '((meeting accounting (Monday 9am))
+ (meeting administration (Monday 10am))
+ (meeting computer (Wednesday 3pm))
+ (meeting administration (Friday 1pm))
+ (meeting whole-company (Wednesday 4pm))))
+
+(define meeting-query
+ '(meeting ?div (Friday . ?time)))
+
+(define meeting-time-def
+ '(rule (meeting-time ?person ?day-and-time)
+ (or
+ (and
+ (job ?person (?div . ?rest))
+ (meeting ?div ?day-and-time))
+ (meeting whole-company ?day-and-time))))
+
+(define meeting-time-query
+ '(meeting-time (Hacker Alyssa P) (Wednesday . ?time)))
+
+(rule (append-to-form () ?y ?y))
+(rule (append-to-form () (?u . ?v) ?y (?u . ?z))
+ (append-to-form ?v ?y ?z))
+
+#| 4.61 |#
+#| 4.62 |#
+#| 4.63 |#
+
+;; How the Query System Works
+
+;; Is Logic Programming Mathematical Logic
+
+#| 4.64 |#
+#| 4.65 |#
+#| 4.66 |#
+#| 4.67 |#
+#| 4.68 |#
+#| 4.69 |#
+
+;; Implementing the Query System
+
+(define (stream-car stream) (car stream))
+
+(define (stream-cdr stream) (force (cdr stream)))
+
+(#%provide stream-map)
+(define (stream-map proc s)
+ (if (stream-null? s)
+ the-empty-stream
+ (cons-stream
+ (proc (stream-car s))
+ (stream-map proc (stream-cdr s)))))
+
+(define (stream-for-each proc s)
+ (if (stream-null? s)
+ 'done
+ (begin
+ (proc (stream-car s))
+ (stream-for-each proc (stream-cdr s)))))
+
+(define (display-stream s)
+ (stream-for-each display-line s))
+
+(define (display-line x)
+ (newline)
+ (display x))
+
+(define (stream-append s1 s2)
+ (if (stream-null? s1)
+ s2
+ (cons-stream
+ (stream-car s1)
+ (stream-append (stream-cdr s1) s2))))
+
+(define (prompt-for-input string)
+ (newline)
+ (newline)
+ (display string)
+ (newline))
+
+(define input-prompt ";;; Query input:")
+(define output-prompt ";;; Query results:")
+
+(#%provide query-driver-loop-init)
+(define (query-driver-loop-init facts)
+ (if (null? facts)
+ (query-driver-loop)
+ (let ((q (query-syntax-process (car facts))))
+ (cond
+ ((assertion-to-be-added? q)
+ (add-rule-or-assertion! (add-assertion-body q))
+ (newline)
+ (display "Assertion added to data base.")
+ (query-driver-loop-init (cdr facts)))
+ (else
+ (query-driver-loop-init (cdr facts)))))))
+
+(#%provide query-driver-loop)
+(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))
+
+(define (make-table-object)
+ (let
+ ((local-table (list '*table*)))
+ (define (lookup key-1 key-2)
+ (let
+ ((subtable (assoc key-1 (cdr local-table))))
+ (if subtable
+ (let
+ ((record (assoc key-2 (cdr subtable))))
+ (if record
+ (cdr record)
+ false))
+ false)))
+ (define (insert! key-1 key-2 value)
+ (let
+ ((subtable (assoc key-1 (cdr local-table))))
+ (if subtable
+ (let
+ ((record (assoc key-2 (cdr subtable))))
+ (if record
+ (set-cdr! record value)
+ (set-cdr!
+ subtable
+ (cons
+ (cons key-2 value)
+ (cdr subtable)))))
+ (set-cdr!
+ local-table
+ (cons
+ (list key-1 (cons key-2 value))
+ (cdr local-table)))))
+ 'ok)
+ (define (dispatch m)
+ (cond
+ ((eq? m 'lookup-proc) lookup)
+ ((eq? m 'insert-proc!) insert!)
+ (else (error "Unknown operation -- TABLE" m))))
+ dispatch))
+
+(define operation-table (make-table-object))
+
+(define get (operation-table 'lookup-proc))
+
+(define put (operation-table 'insert-proc!))
+
+(define (qeval query frame-stream)
+ (let ((qproc (get (type query) 'qeval)))
+ (if qproc
+ (qproc (contents query) frame-stream)
+ (simple-query query frame-stream))))
+
+(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))
+
+(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)
+
+(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 ns (make-base-namespace))
+
+(define (execute exp)
+ (apply
+ (eval (predicate exp) ns)
+ (args exp)))
+
+(define (always-true ignore frame-stream) frame-stream)
+
+(put 'always-true 'qeval always-true)
+
+(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))))
+
+(define (apply-rules pattern frame)
+ (stream-flatmap
+ (lambda (rule)
+ (apply-a-rule rule pattern frame))
+ (fetch-rules pattern frame)))
+
+(define (apply-a-rule rule query-pattern query-frame)
+ (let ((clean-rule (rename-variables-in rule)))
+ (let
+ ((unify-result
+ (unify-match
+ query-pattern
+ (conclusion clean-rule)
+ query-frame)))
+ (if (eq? unify-result 'failed)
+ the-empty-stream
+ (qeval
+ (rule-body clean-rule)
+ (singleton-stream unify-result))))))
+
+(define (rename-variables-in rule)
+ (let ((rule-application-id (new-rule-application-id)))
+ (define (tree-walk exp)
+ (cond
+ ((var? exp)
+ (make-new-variable exp rule-application-id))
+ ((pair? exp)
+ (cons
+ (tree-walk (car exp))
+ (tree-walk (cdr exp))))
+ (else exp)))
+ (tree-walk rule)))
+
+(define (unify-match p1 p2 frame)
+ (cond
+ ((eq? frame 'failed) 'failed)
+ ((equal? p1 p2) frame)
+ ((var? p1) (extend-if-possible p1 p2 frame))
+ ((var? p2) (extend-if-possible p2 p1 frame))
+ ((and (pair? p1) (pair? p2))
+ (unify-match
+ (cdr p1)
+ (cdr p2)
+ (unify-match (car p1) (car p2) frame)))
+ (else 'failed)))
+
+(define (extend-if-possible var val frame)
+ (let ((binding (binding-in-frame var frame)))
+ (cond
+ (binding
+ (unify-match (binding-value binding) val frame))
+ ((var? val)
+ (let ((binding (binding-in-frame val frame)))
+ (if binding
+ (unify-match var (binding-value binding) frame)
+ (extend var val frame))))
+ ((depends-on? val var frame) 'failed)
+ (else (extend var val frame)))))
+
+(define (depends-on? exp var frame)
+ (define (tree-walk e)
+ (cond
+ ((var? e)
+ (if (equal? var e)
+ true
+ (let ((b (binding-in-frame e frame)))
+ (if b
+ (tree-walk (binding-value b))
+ false))))
+ ((pair? e)
+ (or (tree-walk (car e)) (tree-walk (cdr e))))
+ (else false)))
+ (tree-walk exp))
+
+(define THE-ASSERTIONS the-empty-stream)
+
+(define (fetch-assertions pattern frame)
+ (if (use-index? pattern)
+ (get-indexed-assertions pattern)
+ (get-all-assertions)))
+
+(define (get-all-assertions) THE-ASSERTIONS)
+
+(define (get-indexed-assertions pattern)
+ (get-stream (index-key-of pattern) 'assertion-stream))
+
+(define (get-stream key1 key2)
+ (let ((s (get key1 key2)))
+ (if s s the-empty-stream)))
+
+(define THE-RULES the-empty-stream)
+
+(define (fetch-rules pattern frame)
+ (if (use-index? pattern)
+ (get-indexed-rules pattern)
+ (get-all-rules)))
+
+(define (get-all-rules) THE-RULES)
+
+(define (get-indexed-rules pattern)
+ (stream-append
+ (get-stream (index-key-of pattern) 'rule-stream)
+
+ (get-stream '? 'rule-stream)))
+
+(define (add-rule-or-assertion! assertion)
+ (if (rule? assertion)
+ (add-rule! assertion)
+ (add-assertion! assertion)))
+
+(define (add-assertion! assertion)
+ (store-assertion-in-index assertion)
+ (let ((old-assertions THE-ASSERTIONS))
+ (set! THE-ASSERTIONS
+ (cons-stream assertion old-assertions))
+ 'ok))
+
+(define (add-rule! rule)
+ (store-rule-in-index rule)
+ (let ((old-rules THE-RULES))
+ (set! THE-RULES (cons-stream rule old-rules))
+ 'ok))
+
+(define (store-assertion-in-index assertion)
+ (if (indexable? assertion)
+ (let ((key (index-key-of assertion)))
+ (let
+ ((current-assertion-stream
+ (get-stream key 'assertion-stream)))
+ (put
+ key
+ 'assertion-stream
+ (cons-stream
+ assertion
+ current-assertion-stream))))))
+
+(define (store-rule-in-index rule)
+ (let ((pattern (conclusion rule)))
+ (if (indexable? pattern)
+ (let ((key (index-key-of pattern)))
+ (let
+ ((current-rule-stream
+ (get-stream key 'rule-stream)))
+ (put
+ key
+ 'rule-stream
+ (cons-stream
+ rule
+ current-rule-stream)))))))
+
+(define (indexable? pat)
+ (or
+ (constant-symbol? (car pat))
+ (var? (car pat))))
+
+(define (index-key-of pat)
+ (let ((key (car pat)))
+ (if (var? key) '? key)))
+
+(define (use-index? pat) (constant-symbol? (car pat)))
+
+(define (stream-append-delayed s1 delayed-s2)
+ (if (stream-null? s1)
+ (force delayed-s2)
+ (cons-stream
+ (stream-car s1)
+ (stream-append-delayed
+ (stream-cdr s1)
+ delayed-s2))))
+
+(define (interleave-delayed s1 delayed-s2)
+ (if (stream-null? s1)
+ (force delayed-s2)
+ (cons-stream
+ (stream-car s1)
+ (interleave-delayed
+ (force delayed-s2)
+ (delay (stream-cdr s1))))))
+
+(define (stream-flatmap proc s)
+ (flatten-stream (stream-map proc s)))
+
+(define (flatten-stream stream)
+ (if (stream-null? stream)
+ the-empty-stream
+ (interleave-delayed
+ (stream-car stream)
+ (delay (flatten-stream (stream-cdr stream))))))
+
+(define (singleton-stream x)
+ (cons-stream x the-empty-stream))
+
+(define (type exp)
+ (if (pair? exp)
+ (car exp)
+ (error "Unknown expression TYPE" exp)))
+
+(define (contents exp)
+ (if (pair? exp)
+ (cdr exp)
+ (error "Unknown expression CONTENTS" exp)))
+
+(define (assertion-to-be-added? exp)
+ (eq? (type exp) 'assert!))
+
+(define (add-assertion-body exp) (car (contents exp)))
+
+(define (empty-conjunction? exps) (null? exps))
+
+(define (first-conjunct exps) (car exps))
+
+(define (rest-conjuncts exps) (cdr exps))
+
+(define (empty-disjunction? exps) (null? exps))
+
+(define (first-disjunct exps) (car exps))
+
+(define (rest-disjuncts exps) (cdr exps))
+
+(define (negated-query exps) (car exps))
+
+(define (predicate exps) (car exps))
+
+(define (args exps) (cdr exps))
+
+(define (rule? statement)
+ (tagged-list? statement 'rule))
+
+(define (conclusion rule) (cadr rule))
+
+(define (rule-body rule)
+ (if (null? (cddr rule)) '(always-true) (caddr rule)))
+
+(define (query-syntax-process exp)
+ (map-over-symbols expand-question-mark exp))
+
+(define (map-over-symbols proc exp)
+ (cond
+ ((pair? exp)
+ (cons
+ (map-over-symbols proc (car exp))
+ (map-over-symbols proc (cdr exp))))
+ ((symbol? exp) (proc exp))
+ (else exp)))
+
+(define (expand-question-mark symbol)
+ (let ((chars (symbol->string symbol)))
+ (if (string=? (substring chars 0 1) "?")
+ (list
+ '?
+ (string->symbol
+ (substring chars 1 (string-length chars))))
+ symbol)))
+
+(define (var? exp) (tagged-list? exp '?))
+
+(define (constant-symbol? exp) (symbol? exp))
+
+(define rule-counter 0)
+
+(define (new-rule-application-id)
+ (set! rule-counter (+ 1 rule-counter))
+ rule-counter)
+
+(define (make-new-variable var rule-application-id)
+ (cons '? (cons rule-application-id (cdr var))))
+
+(define (contract-question-mark variable)
+ (string->symbol
+ (string-append
+ "?"
+ (if (number? (cadr variable))
+ (string-append
+ (symbol->string (caddr variable))
+ "-"
+ (number->string (cadr variable)))
+ (symbol->string (cadr variable))))))
+
+(define (make-binding variable value)
+ (cons variable value))
+
+(define (binding-variable binding) (car binding))
+
+(define (binding-value binding) (cdr binding))
+
+(define (binding-in-frame variable frame)
+ (assoc variable frame))
+
+(define (extend variable value frame)
+ (cons (make-binding variable value) frame))
+
+(define (tagged-list? exp tag)
+ (if (pair? exp)
+ (eq? (car exp) tag)
+ false))
+
+#| 4.70 |#
+
+#| 4.71 |#
+#| 4.72 |#
+#| 4.73 |#
+#| 4.74 |#
+#| 4.75 |#
+#| 4.76 |#
+#| 4.77 |#
+#| 4.78 |#
+#| 4.79 |#