Category : Miscellaneous Language Source Code
Archive   : PCLISP30.ZIP
Filename : MATCH.L
Output of file : MATCH.L contained in archive : PCLISP30.ZIP
;; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;; A DEDUCTIVE DATA BASE RETRIEVER AS PER LISPcraft CHAPTERS 21&22
;; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;; This file called match.l implements all of the functions in
;; chapters 21 and 22 of LISPcraft by R.Wilensky. Together they form
;; a deductive data base retriever with two access functions. One is
;; called (insert) and the other (retrieve). Insert takes implications
;; and base cases and inserts them into the given data base. (retrieve)
;; returns a list of matches made with the data base and any bindings
;; neccssary to make the match true. Hence an output like (nil) means
;; one match requiring no bindings. The functions have been slightly
;; modified to run with PC-LISP. Note that they require the PC-LISP.L
;; file to be loaded specificially for the let macro and a few other
;; goodies. If you put PC-LISP.L in the current directory it will be
;; automatically loaded. Or you can put it in a library directory, see
;; the (load) function.
;;
;; August 22nd 1986
;; Peter Ashwood-Smith
;;
;; Example queries:
;; (mammal Fido) gives (nil) meaning Yes he is a mammal
;; (dog ?x) gives (?x Fido) meaning Yes if (?x is Fido)
;; (mammal ?x) etc.. you get the idea.
;; (? Fido)
;;
;; You really cannot get much out of this example unless you get
;; the LISPcraft book. Have Fun!
;;
;; Main processing Loop - input a data base query, expand the variables
;; ?x to (*var* x) as the read macro in LISPcraft page 295 would do then
;; pass the request to the (retrieve) function.
;;
(setsyntax '|?| 'vmacro '(lambda()(list '*var* (read))))
(setq displace-macros t) ;runs much faster if let is displaced at eval time
(defun ProcessQueries (data-base)
(prog (InputQuery)
loop (princ "query?")
(setq InputQuery (read))
(cond ((null InputQuery) (return)))
(princ "ans=")
(patom (CompressVariables (retrieve InputQuery data-base)))
(princ (ascii 10))
(go loop)
)
)
;;
;; Opposite of Read Macro for ? - turn list elements like (*var* x) into
;; ?x
;;
(defun CompressVariables (List)
(cond ((null List) ())
((atom List) List)
((eq (car List) '*var*)
(implode (list '|?| (cadr List)))
)
(t (cons(CompressVariables(car List))(CompressVariables (cdr List))))
)
)
;;
;; top level matcher function, just drives the recursive next level
;; by setting bindings to nil.
;;
(defun match (pattern1 pattern2)
(match-with-bindings pattern1 pattern2 nil)
)
(defun match-with-bindings (pattern1 pattern2 bindings)
(cond ((pattern-var-p pattern1)
(variable-match pattern1 pattern2 bindings)
)
((pattern-var-p pattern2)
(variable-match pattern2 pattern1 bindings)
)
((atom pattern1)
(cond ((eq pattern1 pattern2)
(list bindings)
)
)
)
((atom pattern2) nil)
(t (let ((car-result
(match-with-bindings
(car pattern1)(car pattern2) bindings)))
(and car-result
(match-with-bindings
(cdr pattern1)
(cdr pattern2)
(car car-result)
)
)
)
)
)
)
(defun variable-match (pattern-var item bindings)
(cond ((equal pattern-var item) (list bindings))
(t (let ((var-binding (get-binding pattern-var bindings)))
(cond (var-binding
(match-with-bindings var-binding item bindings))
((not (contained-in pattern-var item bindings))
(list (add-binding pattern-var item bindings)))
)
)
)
)
)
(defun contained-in (pattern-var item bindings)
(cond ((atom item) nil)
((pattern-var-p item)
(or (equal pattern-var item)
(contained-in pattern-var
(get-binding item bindings)
bindings)
)
)
(t (or (contained-in pattern-var (car item) bindings)
(contained-in pattern-var (cdr item) bindings)
)
)
)
)
(defun add-binding (pattern-var item bindings)
(cons (list pattern-var item) bindings)
)
(defun get-binding (pattern-var bindings)
(cadr (assoc pattern-var bindings))
)
(defun pattern-var-p (item)
(and (listp item) (eq '*var* (car item)))
)
;;
;; Fast Data Base Manager Operations. Using matcher function above to perform
;; deductive retreival. Indexing as per LISPcraft chapter 22.
;;
(defun replace-variables(item)
(let ((!bindings ()))
(replace-variables-with-bindings item)))
(defun replace-variables-with-bindings(item)
(cond ((atom item) item)
((pattern-var-p item)
(let ((var-binding (get-binding item !bindings)))
(cond (var-binding)
(t (let ((newvar (makevar (gensym 'var))))
(setq !bindings
(add-binding item newvar !bindings))
newvar))
)
)
)
(t (cons (replace-variables-with-bindings (car item))
(replace-variables-with-bindings (cdr item))
)
)
)
)
(defun makevar (atom)
(list '*var* atom)
)
(defun query (request data-base)
(apply 'append (mapcar '(lambda(item)(match item request))
data-base
)
)
)
(defun index (item data-base)
(let ((place (cond ((atom (car item)) (car item))
((pattern-var-p (car item)) '*var*)
(t '*list*)
)
)
)
(putprop place (cons (replace-variables item)(get place data-base))
data-base)
(putprop data-base
(enter place (get data-base '*keys*))
'*keys*)
)
)
(defun enter (e l)
(cond ((not (memq e l)) (cons e l))
(t l)
)
)
(defun fast-query (request data-base)
(cond ((pattern-var-p (car request))
(apply 'append
(mapcar '(lambda(key)(query request (get key data-base)))
(get data-base '*keys*)
)
)
)
(t (append
(query request (get (cond ((atom (car request))
(car request)
)
(t '*list*)
)
data-base
)
)
(query request (get '*var* data-base))
)
)
)
)
;;
;; deductive retreiver (LISPcraft page 314) use backward chaining to establish
;; bindings.
;;
(defun retrieve (request data-base)
(append
(fast-query request data-base)
(apply 'append
(mapcar '(lambda(bindings)
(retrieve
(substitute-vars
(get-binding '(*var* antecedent) bindings)
bindings)
data-base))
(fast-query (list '<- request '(*var* antecedent))
data-base)
)
)
)
)
;;
;; substitute variables for bindings recursively. LISPcraft page 315.
;;
(defun substitute-vars (item bindings)
(cond ((atom item) item)
((pattern-var-p item)
(let ((binding (get-binding item bindings)))
(cond (binding (substitute-vars binding bindings))
(t item)
)
)
)
(t (cons (substitute-vars (car item) bindings)
(substitute-vars (cdr item) bindings)
)
)
)
)
;;
;; page 315 of LISPcraft add too !d-b1!
;; by calling index to insert the implications and base cases.
;;
(index '(<- (scales ?x) (fish ?x)) '!d-b1!) ; fishes have scales
(index '(<- (fins ?x) (fish ?x)) '!d-b1!) ; fishes have fins
(index '(<- (legs ?x) (mammal ?x)) '!d-b1!) ; some mammals have legs
(index '(<- (mammal ?x) (dog ?x)) '!d-b1!) ; a dog is a mammal
(index '(<- (dog ?x) (poodle ?x)) '!d-b1!) ; a poodle is a dog
(index '(poodle Fido) '!d-b1!) ; fido is a poodle
(index '(horse Terry) '!d-b1!) ; terry is a horse
(index '(fish Eric) '!d-b1!) ; Eric is a fish
;;
;; start processing queries from data base #1 which was entered above
;; some good things to try are (mammal Fido) which will return (nil)
;; meaning that one match was found needing no bindings to make it true.
;; this was established via the chain (poodle Fido)-->(dog Fido)-->
;; (mammal Fido).
;;
(defun run() (ProcessQueries '!d-b1!))
(princ "Data Base Retreiver Loaded and Ready To Go")
(princ (ascii 10))
(princ "Just type (run) to start it, have fun.")
(princ (ascii 10))
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/