# 09 Examples Functional Programming. Tower of Hanoi AB C.

## Presentation on theme: "09 Examples Functional Programming. Tower of Hanoi AB C."— Presentation transcript:

09 Examples Functional Programming

Tower of Hanoi AB C

> (tower-of-hanoi (3 2 1) a b c) ; a b c 7 (defun tower-of-hanoi (disks from to spare) ) (if (endp disks) xxx ; return 0 ( ) ooo ; )

Tower of Hanoi xxx? 0 (, return 0) ooo? n-1 spare ? (tower-of-hanoi (rest disks ) from spare to) to ? 1 n-1 to ? (tower-of-hanoi (rest disks ) spare to from)

Tower of Hanoi (defun tower-of-hanoi (disks from to spare) (if (endp disks) 0 (+ (tower-of-hanoi (rest disks) from spare to) 1 (tower-of-hanoi (rest disks) spare to from) )

Tower of Hanoi > (tower-of-hanoi (3 2 1) a b c) ; a b c Move 1 from A to B. Move 2 from A to C. Move 1 from B to C. Move 3 from A to B. Move 1 from C to A. Move 2 from C to B. Move 1 from A to B. NIL

Tower of Hanoi ooo n-1 spare ? (tower-of-hanoi (rest disks ) from spare to) to ? 1 n-1 to ? (tower-of-hanoi (rest disks ) spare to from) -> 1 (format t Move ~A from ~A to ~A.~% (car disks) from to) + (progn ).. if unless.. prog

Tower of Hanoi (defun tower-of-hanoi (disks from to spare) (unless (endp disks) (tower-of-hanoi (rest disks) from spare to) (format t "Move ~A from ~A to ~A.~%" (car disks) from to) (tower-of-hanoi (rest disks) spare to from) )

Inference - Matching > (match (p a b c a) (p ?x ?y c ?x)) ((?Y. B) (?X. A)) T > (match (p ?x b ?y a) (p ?y b c a)) ((?Y. C) (?X. ?Y)) T > (match (a b c) (a a a)) NIL > (match (p ?x) (p ?x)) NIL T > (match (p ?v b ?x d (?z ?z)) (p a ?w c ?y (e e)) ((?v. a) (?w. b))) ((?Z. E) (?Y. D) (?X. C) (?V. A) (?W. B)) T > (match (?x a) (?y ?y)) ((?Y. A) (?X. ?Y)) T

Inference - Matching match If x and y are eql, then match; otherwise, If x is a variable that has a binding, they match if it matches y; otherwise, If y is a variable that has a binding, they match if it matches x; otherwise, If x is a variable(without a binding), they match and thereby establish a binding for it; otherwise, If y is a variable(without a binding), they match and thereby establish a binding for it; otherwise, They match if they are both conses, and the cars match, and the cdrs match with the bindings generated thereby.

Inference - Matching symbol (symbolp x) Symbol ? (eql (char (symbol-name x) 0) #\?) (defun var? (x) (and (symbolp x) (eql (char (symbol-name x) 0) #\?)))

Inference - Matching assoc > (setq x (cons a b)) (A. B) > (setq y (cons c d)) (C. D) > (setq q (list x y)) ((A. B) (C. D)) > (assoc a q) (A. B)

Inference - Matching If x and y are eql, then match; ((eql x y) (values binds t)) If x is a variable that has a binding, they match if it matches y; ((assoc x binds) (match (binding x binds) y binds)) If y is a variable that has a binding, they match if it matches x; ((assoc y binds) (match x (binding y binds) binds)) If x is a variable (without a binding), they match and thereby establish a binding for it; ((var? x) (values (cons (cons x y) binds) t)) ; bind( x) binds If y is a variable (without a binding), they match and thereby establish a binding for it; ((var? y) (values (cons (cons y x) binds) t)) ; bind ( y) binds

Inference - Matching They match if they are both conses, and the cars match, and the cdrs match with the bindings generated thereby. (when (and (consp x) (consp y)) ;x y cons (multiple-value-bind (b2 yes) ; b2 yes bind (match (car x) (car y) binds) ;(car x) (car y) match (and yes (match (cdr x) (cdr y) b2)))) ; (car x) (car y) match, yes T, ; match (cdr x) (cdr y), binding b2

Inference - Matching (defun match (x y &optional binds) (cond ((eql x y) (values binds t)) ((assoc x binds) (match (binding x binds) y binds)) ((assoc y binds) (match x (binding y binds) binds)) ((var? x) (values (cons (cons x y) binds) t)) ((var? y) (values (cons (cons y x) binds) t)) (t (when (and (consp x) (consp y)) (multiple-value-bind (b2 yes) (match (car x) (car y) binds) (and yes (match (cdr x) (cdr y) b2)))))))

Inference - Matching binding (defun binding (x binds) (let ((b (assoc x binds))) ; binds x, (x, ) (if b ;, bind (cdr b) (or (binding (cdr b) binds) ; (cdr b) bind, (, ) (cdr b))))) ; bind, (cdr b),

Inference - Answering Queries > (parent ?x ?y) (((?x. donald) (?y. nancy)) <- rule fact return predicate rule > (<- (parent donald nancy)) 1 > (<- (child ?x ?y) (parent ?y ?x)) 1

Inference - Answering Queries (defvar *rules* (make-hash-table)) ; hash table (defmacro <- (con &optional ant) ; <- `(length (push (cons (cdr ',con) ',ant) (gethash (car ',con) *rules*)))) If you prefix a comma to something within a ` (backquoated) expression, it will be evaluated > `(a b c) (A B C) > (setf a 1 b 2) 2 > `(a is,a and b is,b) (A IS 1 AND B IS 2)

Inference - Answering Queries (defun prove (expr &optional binds) ;expr (parent ?x ?y) (and ( ) ( ) ( )) (case (car expr) ; rule( and or not) (and (prove-and (cdr expr) binds)) (or (prove-or (cdr expr) binds)) (not (prove-not (cadr expr) binds)) (t (prove-simple (car expr) (cdr expr) binds)))) ; rule, (parent ?x ?y) (defun prove-simple (pred args binds) ; parent (?x ?y) binds (mapcan #'(lambda (r) (multiple-value-bind (b2 yes) ; match binding (match args (car r) ; b2 yes binds) (when yes ; binding (if (cdr r) ; rule, r (and (male ?x) ( ) ) (prove (cdr r) b2) ; b2 binds, prove (list b2))))) ;return (b2) (mapcar #change-vars ; pred key rule, (gethash pred *rules*)))) ;

Inference - Answering Queries > (prove-simple 'parent ' (donald nancy) nil) (NIL) ; binding prove > (prove-simple 'child '(?x ?y) nil) (((#:?6. NANCY) (#:?5. DONALD) (?Y. #:?5) (?X. #:?6))) ; binding

Inference - Answering Queries (defun change-vars (r) (sublis (mapcar #'(lambda (v) (cons v (gensym "?"))) (vars-in r)) r)) ; r ?xxxx (defun vars-in (expr) ; expr (if (atom expr) (if (var? expr) (list expr)) (union (vars-in (car expr)) (vars-in (cdr expr)))))

Inference - Answering Queries (defun prove-and (clauses binds) (if (null clauses) ; clauses null (list binds) ; return binds (mapcan # (lambda (b) (prove (car clauses) b)) ; clause prove (prove-and (cdr clauses) binds)))) ; clause prove-and (defun prove-or (clauses binds) (mapcan #(lambda (c) (prove c binds)) ; clause clauses)) ; prove (defun prove-not (clause binds) ;clause (unless (prove clause binds) ; prove, binds (list binds))) ;prove binds

Inference - Answering Queries (defmacro with-answer (query &body body) (let ((binds (gensym))) ;, g1 (dolist (,binds (prove,query)) ; prove binding (let,(mapcar #(lambda (v) ; g1 (,v (binding ',v,binds))) (vars-in query)),@body)))) ;query:, (parent ?x ?y) ;body : binding ;,@ body evaluate elements > (prove '(parent ?x ?y)) (((?Y. DEBBIE) (?X. DONALD)) ((?Y. NANCY) (?X. DONALD)))

Inference - Answering Queries (with-answer (p ?x ?y) (f ?x ?y)) is macroexpanded into: (dolist (#:g1 (prove (p ?x ?y))) (let ((?x (binding ?x #:g1)) (?y (binding ?y #:g1))) (f ?x ?y))) > (with-answer (parent ?x ?y) (format t ~A is the parent of ~A. ~% ?x ?y)) DONALD is the parent of NANCY. NIL

Inference - Analysis If we do a (clrhash *rules*) and then define the following rules and facts, hash table *rule* (<- (parent donald nancy)) (<- (parent donald debbie)) (<- (male donald)) (<- (father ?x ?y) (and (parent ?x ?y) (male ?x))) (<- (= ?x ?x)) (<- (sibling ?x ?y) (and (parent ?z ?x) (parent ?z ?y) (not (= ?x ?y))))

Inference - Analysis : we will be able to make inferences like the following: > (with-answer (father ?x ?y) (format t "~A is the father of ~A. ~% ?x ?y)) DONALD is the father of DEBBIE. DONALD is the father of NANCY. NIL > (with-answer (sibling ?x ?y) (format t "~A is the sibling of ~A. ~% ?x ?y)) DEBBIE is the sibling of NANCY. NANCY is the sibling of DEBBIE. NIL