home *** CD-ROM | disk | FTP | other *** search
- ;; MATCH.L for PC-LISP.EXE (V2.13)
- ;; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ;; 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))
-