COMMON LISP Symbolic Expressions • The syntactic elements of the LISP programming language are symbolic expressions. – Known as s-expressions. – Both programs and data are represented as s-expressions. – S-expressions may be either an atom or a list. • LISP atoms are the basic syntactic units of the language and include both numbers and symbols. • Symbolic atoms are composed of letters, numbers, and the following non-alphanumeric characters: *-+/@%^&_M<>~ • Examples of LISP atoms include: 3.1416 100 X Hyphenated -name *some-global* nil • A list is a sequence of either atoms or other lists separated by blanks and enclosed in parentheses. Examples of lists include: (1 2 3 4) (tom marry john joyce) (a (b c) (d (e f))) () • Lists may be elements of lists • The empty list, “( )”, plays a special role in the construction and manipulation of LISP data structures and is given the special name nil. • Nil is the only s-expression that is considered to be both an atom and a list. Lists are extremely flexible tools for constructing representational structures. For example, we can use lists to represent expressions in the predicate calculus: (on block -1 table) (likes bill X) (and (likes george kate) (likes bill merry)) • An important feature of LISP is its use of LISP syntax to represent programs as well as data. For example, the lists, (*79) ( - (+ 3 4 ) 7) • With (* 7 9) representing the product of 7 and 9. > (* 7 9 ) 63 > • When given a list, the LISP evaluator attempts-to interpret the first element of the list as the name of a function and the remaining elements as its arguments. • The value printed by LISP is the result of applying the function to its arguments. > (+ 14 5) 19 > (+ 1 2 3 4) 10 > (- (+ 3 4) 7) 0 > (* (+ 2 5) ) (- 7 (/ 21 7)) 28 > (= (+ 2 3 ) 5)) t > ( a b c) Error: invalid function:a • In evaluating a function, LISP first evaluates its arguments and then applies the function indicated by the first element of the expression to the results of these evaluations. • If the arguments are themselves function expressions, LISP applies this rule recursively to their evaluation. • LISP uses the convention that numbers always evaluate to themselves. If, for example, 5 is typed into the LISP interpreter, LISP will respond with 5. • Symbols, such as X, may have a value bound to them. If a symbol is bound, the binding is returned when the symbol is evaluated. • If a symbol is unbound, it is an error to evaluate that symbol. • For example, in evaluating the expression (+ (* 2 3 ) (* 3 5)) • LISP first evaluates the arguments, (* 2 3) and (* 3 5). • In evaluating (* 2 3), LISP evaluates the arguments 2 and 3, which return their respective arithmetic values; these values are multiplied to yield 6. • Similarly, (* 3 5) evaluates to 15) • These results are then passed to the top-level addition, which is evaluated, returning 21. • LISP includes a large number of functions that operate on lists. • These includes functions:– To construct and combine lists – To Access elements of lists – To test various properties of lists. • For example, list takes any number of arguments and constructs a list of those elements. • ‘nth’ takes a number and a list as arguments and returns indicated element of the list. • By convention, nth begins counting with 0. • Examples of these and other list manipulation functions include: > (list 1 2 3 4 5) ( 1 2 3 4 5) > (nth 0 ‘(a b c d) a > (nth 2 (list 1 2 3 4 5) 3 > (nth 2 ‘((a 1) (b 2) (c 3) (d 4))) (c 3) > (length (a b c d)) 4 > (member 7 ‘(1 2 3 4 5)) nil > (null ( )) t • A form is an s-expression that is intended to be evaluated. If it is a list, the first element is treated as the function name and the subsequent elements are evaluated to obtain the function arguments. • In evaluating an s-expression: – If the s-expression is a number, return the value of the number. – If the s-expression is an atomic symbol, return the value bound to that symbol; if it is not bound it is an error. – If the s-expression is a list, evaluate the second through the last arguments and apply the function indicated by the first argument to the results. Control of LISP Evaluation quote and eval • The function quote is to prevent evaluation of an s-expression that should be treated as data rather than an evaluable form. • Quote takes one argument and returns that argument without evaluating it. For example: > (quote (a b c)) (a b c ) > (quote (+ 1 3)) (+ 1 3) • Because quote is used so often, LISP allows it to be abbreviated by a single quotation mark. Thus, the preceding examples could be written: > ‘(a b c) (a b c) > ‘(+ 1 3) (+ 1 3) • Consider the effect of quote in the following calls to the list function: > (list (+ 1 2) (+ 3 4) (3 7) > (list ‘(+ 1 2) ‘(+ 3 4)) ((+1 2) (+ 3 4)) • As a complement to quote, LISP also provides a function, eval. • Eval takes one s-expression as an argument: this argument is evaluated as is usual for arguments to function; however, the result is then evaluated again and this final result is returned as the value of the eval expression. • Examples of the behavior of eval and quote include: > (quote (+ 2 3)) (+ 2 3) > (eval (quote (+ 2 3))) 5 > (list ‘* 2 5)) (* 2 5) > (eval (list ‘* 2 5 ) 10 Creating New Functions • Common LISP includes a large number of built-in functions, including: – A full range of arithmetic functions, integer, rational, real and complex arithmetic. – A variety of looping and program control functions – List manipulation and other data structuring functions. – Input/output functions – Forms for the control of functions evaluation. – Functions for the control of the environment and operating system. • In LISP, we program by defining new functions. • These new functions are defined using defun, which is short for define function. • Once a function is defined it may be used in the same fashion as functions that are built into the language. • For example, the user would like to define a function called square that takes a single argument and returns the square of that argument. Square may be carried by having LISP evaluate the following expression: (defun square (X) (* X X)) • The first argument to defun is the name of the function being defined. • The second is a list of the formal parameters for that function, which must all be symbolic atoms. • The remaining arguments are zero or more s-expressions, which constitute the body of the new function, the LISP code that actually defines its behavior. • In the above example, square is defined as a function that takes one argument and returns the result of multiplying that argument by itself. More concisely, the syntax of a defun expression is: (defun <function name> (<formal parameters>) <function body>) • A newly defined function may be used just like any built-in function. • For example, that we need a function to compute the length of the hypotenuse of a right triangle given the lengths of the other two sides. This function may be defined according to the Pythagorean theorem, using the previously defined square function along with the built-in function sqrt. (defun hypotenuse (X Y) (sqrt (+ (square X) (square Y))) ;the length of the hypotenuse is ; the square root of the sum of ; the squares of the other sides Program Control in LISP Conditionals and Predicates • LISP branching is also based on function evaluation: control functions perform test and, depending on the results, selectively evaluate alternative forms. • For example, the following definition of the absolute value function (defun absolute-value (x) (cond ((< x O) (- x)) ((>= x O) x ))) • The example uses the function cond, to implement a conditional branch. Cond takes as arguments a number of condition-action pairs: (cond ((condition 1) (action 1)) ((condition 1) (action 1)) ((condition 1) (action 1)) … … … … ((condition n) (action n))) • Conditions and actions may be arbitrary s-expression • It evaluates the conditions in order until one of them returns a nonnil value. • When this occurs, it evaluates the associated action and returns this result a side value of the cond expression. • None of the other actions and none of the subsequent conditions are evaluated. • If all of the conditions evaluate to nil, cond returns nil. • An alternative definition of absolute-value is: (defun absolute-value (x) (cond ((< x 0) (- x)) ( t x ))) ; if X is less than O, return -X ; otherwise, return X unchanged • This version notes that the second condition (>= X 0), is always true if the first is false. The “t” atom in the final condition of the cond statement is a LISP atom that corresponds to “true”. T always evaluates to itself. • This construct is extremely useful, as it provides a way of giving a cond statement a default action that is evaluated if and only if all preceding conditions fail. • Although any evaluable s-expressions may be used as the conditions of a cond, generally these are a particular kind of LISP function called a predicate. • A predicate is simply a function that returns a value of either true or false depending on whether or not its arguments possess some property. • The most obvious examples of predicates are the relational operators typically used in arithmetic such as =, >, and >=. • Here are some examples of arithmetic predicates in LISP; > (= 9 (+ 4 5)) t > (> = 17 4) t > (< 8 (+ 4 2 )) nil > ( oddp 3) ;oddp tests whether its argument is odd or not. t > (minusp 6) ; minusp tests whether its argument is less than 0 nil > (numberp 17) ; numberp tests whether its argument is numeric t > (numberp nil) nil > (zerop 0) ; zerop is true it its argument is 0, nil otherwise t > (plusp 10) ; plusp is true if its argument is strictly greater than 0 t > (plusp -2) nil • Note that the predicates in the above examples return t or nil. • If form takes three arguments. – The first is a test. If evaluates the test. – If it returns a non-nil value, the if form evaluates its second argument and returns the result. – Otherwise it returns the result of evaluating the third arguments. • For example, absolute-value could be defined using the if form: (defun absolute-value (x) (if (< x 0) (- x) x)) And form, evaluates its arguments in left-to-right order, stopping when any one of the arguments evaluates to nil or the last argument has been evaluated. Upon completion, the and form returns the value of the last argument evaluated. (AND (arg1) (arg2)…(argn)) > (and (oddp 2) (print “second statement was evaluated”)) nil > (and (oddp 3) (print “second statement was evaluated”)) second statement was evaluated OR Or form evaluates its argument only until a non-nil value is encountered, returning this value as a result. (OR (arg1) (arg2)…(argn)) > (or (oddp 3) ( print “second statement was evaluated”)) t > (or (oddp 2) (print “second statement was evaluated”)) second statement was evaluated Lists as Recursive Structures • The basic functions for accessing the components of lists are car and cdr. • car takes a single argument, which must be list, and returns the first element of that list. • cdr also takes a single argument, which must be a list, and returns that list with its first argument removed. • For example: > (car ‘(a b c)) a > (cdr ‘(a b c)) (b c) > (car ‘((a b) (c d))) ; the first element of a list may be a list ( a b) > (cdr ‘((a b) (c d))) ((c d)) > (car (cdr ‘ (a b c d))) b • Common LISP includes the predicate member, which determines whether one s-expression is a member of a list, • And length, which determines the length of a list. • We may define our own versions of these functions. • My-member takes two arguments, and arbitrary sexpression and a list. • It returns nil if the s-expression is not a member of the list • Otherwise it returns the portion of the list containing the s-expression as its first element: (defun my-member (element list) (cond ((null list) nil) ((equal element (car list)) list) (t (my-member element (cdr list))))) My-member has the behavior: > (my-member 4 ‘ ( 1 2 3 4 5 6)) (4 5 6) > (my-member 5 ‘ (a b c d)) nil • Similarly we define our own versions of length and nth: >(defun my-length (list) (cond ((null list) 0) (t (+ (my-length (cdr list)) 1)))) MY-LENGTH >(my-length '(a b c d e f g)) 7 >(defun my-nth (n list) (cond ((zerop n) (car list)) (t (my-nth (- n 1) (cdr list))))) MY-NTH >(my-nth 4 '(11 22 33 44 55 66 77 88)) 55 cons x y cons is the primitive function to create a new cons whose car is x and whose cdr is y. For example: (cons 'a 'b) => (a b) (cons 'a (cons 'b (cons 'c '()))) => (a b c) (cons 'a '(b c d)) => (a b c d) >(cons '(1 2) '(3 4)) ((1 2) 3 4) • Function cons, takes two s-expressions as arguments, evaluates them, and returns a list whose car is the value of the first argument and whose cdr is the value of the second: > (cons 1 ‘(2 3 4)) (1 2 3 4) > (cons ‘(a b) ‘ (c d e)) ((a b) c d e) • Cons bears an inverse relationship to car and cdr: > (car (cons 1 ‘(2 3 4))) 1 > (cdr (cons 1 ‘(2 3 4))) (2 3 4) • Definition of the function filter-negatives, which takes a list of numbers as an argument and returns that list with any negative numbers removed. (defun filter-negatives (number-list) (cond ((null number-list) nil) ((plusp (car number-list)) (cons (car number-list) (filter-negatives (cdr number-list)))) (t (filter-negatives (cdr number-list))))) This function behaves: > (filter-negatives ‘(1 -1 2 -2 3 -4)) ( 1 2 3) Append (append '(a b c) '(d e f) '( ) '(g)) => (a b d e f g) >(append '(1 2) '(3 4)) (1 2 3 4) Length >(length '(1 2 3)) 3 >(length '((1 2) 3 (1 (4 (5))))) 3 Function to Count Number of Atoms in a List >(defun count-atoms (list) (cond (( null list) 0) ((atom list) 1) (t (+ (count-atoms (car list)) (count-atoms (cdr list)))))) >(count-atoms '((1 2) 3 (1 (4 (5))))) 6 Function to Flatten an Arbitrary Structure >(defun flatten (LIST) (cond ((null LIST) nil) ((atom LIST) (list LIST)) (t (append (flatten (car LIST))(flatten (cdr LIST)))))) >(flatten '((1 2) 3 (1 (4 (5))))) (1 2 3 1 4 5) >(flatten '(a (b c) (((d) e f )))) (A B C D E F) Binding variable using SET/SETQ(Global scope) set ‘symbol value/s-expression >(set 'inc 0) 0 >(defun f(x) (set 'inc(+ inc 1)) (+ x inc)) F >(f 1) 2 >(f 2) 4 setq symbol value/s-expression >(set 'x 0) 0 >(setq x 0) 0 Bound and Free variables >(setq inc 23) >(setq x 100) >inc 23 >x 100 >(defun f(x) (setq inc 1) (+ x inc)) F >(f 0) 1 >inc 1 >x 100 Bound var Free var Defining Local Variable Using LET (let (<local-variables>) <expressions>) Where elements of <local-variables> are:– Symbolic atoms – Pairs of the form: (<symbol><expression>) >(setq a 0) 0 >(let ((a 3) b) (setq b 4) (+ a b)) 7 >a 0 >b error Data Types in Common LISP •Integers •Ratios •Floating point numbers •Strings •Characters •Symbols •Lists •Arrays •Functions •Structures •Others Higher-Order Functions. Functions that take other functions as parameters or return them as results. Filters >(defun filter-negatives(number-list) (cond((null number-list) nil) ((plusp (car number-list))(cons (car numberlist)(filter-negatives (cdr number-list)))) (t (filter-negatives (cdr number-list))))) FILTER-NEGATIVES >(filter-negatives '(1 -1 2 -2 3 -4)) (1 2 3) Higher-Order Functions. Functions that take other functions as parameters or return them as results. Filters >(defun filter-evens(number-list) (cond((null number-list) nil) ((oddp (car number-list))(cons (car number-list) (filter-evens (cdr number-list)))) (t (filter-evens (cdr number-list))))) FILTER-EVENS >(filter-evens '(1 2 3 4 5 6 7 8 9 10)) (1 3 5 7 9) • Because two functions differ only in the name of the predicates used to filter elements from the list, these can be generalized into a single function that takes the filtering predicate as a second parameters. • When a function is passed as a parameter it is preceded by a #’. • This is defined using a LISP form called FUNCALL. (funcall <fn> <arg1> <arg2> ... <argn>) • FUNCALL applies the function fn to the arguments arg1, arg2, ..., argn. >(funcall #'+ 1 2) 3 >(funcall #'car '(a b c)) A >(defun filter(list-of-elements test) (cond ((null list-of-elements) nil) ((funcall test (car list-ofelements))(cons (car list-ofelements) (filter (cdr listof-elements) test))) (t (filter (cdr list-of-elements)test)))) FILTER >(filter '(1 3 -9 5 -2 -7 6) #'plusp) (1 3 5 6) >(filter '(1 2 3 4 5 6 7 8 9 10) #'evenp) (2 4 6 8 10) >(filter '(1 a b 3 c 4 7 d) #'numberp) (1 3 4 7) APPLY This applies function to a list of arguments. (apply <fn> <(arg1, arg2, … , agn)>) >(apply #'+ '(1 2)) 3 >(apply #'car '((a b c))) A >(setq f '+) >(apply f '(1 2)) 3 >(setq f #'-) >(apply f '(1 2)) -1 Higher-Order Functions Maps map result-type function sequence &rest moresequences >(map 'list #'- '(1 2 3 4)) (-1 -2 -3 -4) >(map 'list #'+ '(1 2) '(1 2)) (2 4) >(map 'list #'evenp '(1 2 3 4 5 6 7)) (NIL T NIL T NIL T NIL) >(map 'list #'minusp '(1 -2 3 4 -5 -6)) (NIL T NIL NIL T T) mapcar function list &rest more-lists mapcar operates on successive elements of the lists. First the function is applied to the car of each list, then to the cadr of each list, and so on. >(mapcar #'abs '(3 -4 2 -5 -6)) (3 4 2 5 6) >(mapcar #'cons '(a b c) '(1 2 3)) ((a . 1) (b . 2) (c . 3)) >(mapcar #'1+ '(1 2 3 4 5 6)) (2 3 4 5 6 7) >(mapcar #'+ '(1 2 3 4) '(5 6 7 8)) (6 8 10 12) >(mapcar #'max '(3 9 1 7) '(2 5 6 8)) (3 9 6 8) LAMBDA EXPRESSIONS • In the preceding examples function arguments were passed by their names and applied to a series of arguments. This requires that the functions be previously define in the global environment. • Frequently it is desirable to pass function definitions directly without first defining the function globally. This is made possible through the LAMBDA expression. (lambda (<formal-parameters>) <body>) • LAMBDA expression may be use in place of a function name in a FUNCALL or APPLY. LAMBDA EXPRESSIONS >(funcall #'(lambda (x) (* x x)) 4) 16 >(apply #' (lambda (x y)(+ (* x x) y)) '(2 3)) 7 >(funcall #' (lambda (x) (append x x)) '(a b c)) (A B C A B C) >(funcall #' (lambda (x y) (append x y)) '(a b c)'(1 2 3)) (A B C 1 2 3) LAMBDA EXPRESSIONS >(funcall #'(lambda (x1 x2)(append (reverse x1) x2)) '(a b c)'(d e f)) (C B A D E F) >(mapcar #'(lambda(x)(* x x))'(1 2 3 4 5)) (1 4 9 16 25) >(mapcar #'(lambda(x)(* x 2))'(1 2 3 4 5)) (2 4 6 8 10) LAMBDA EXPRESSIONS >(mapcar #'(lambda(x)(and (> x 0)(< x 10)))'(1 24 5 –9 8 23)) (T NIL T NIL T NIL) >(mapcar #' (lambda (x) (list 'hi 'there x)) '(Sam Fred George)) ((HI THERE SAM) (HI THERE FRED) (HI THERE GEORGE)) LAMBDA EXPRESSIONS >(setq y '(1 2 3)) (1 2 3) >(setq a 100) 100 >(funcall #'(lambda (x) (* x 10)) a) 1000 >(mapcar #'(lambda (x) (* x 10)) y) (10 20 30) >(mapcar #'(lambda (x) (* x a)) y) (100 200 300) FARMER WOLF GOAT AND CABBAG PROBLEM • A farmer comes with his wolf, goat and cabbage to the river bank he wishes to cross with above animals and vegetables. • A boat is available to cross the river. • Boat can carry only two things at a time including the farmer. • If wolf is left alone with the goat, the wolf will eat the goat. • If cabbage is left alone with the goat, the goat will eat the cabbage. • The program searches the space in a depth-first fashion. • States are represented as lists of four elements. Where each element denotes the location of the farmer, wolf, goat, or cabbage respectively. • Farmer, wolf, goat and cabbage => (f w g c) • Thus state (e w e w) represent:– Farmer is on the eastern bank – Wolf is on the western bank. – Goat is on the eastern bank. – Cabbage is on the western bank. ;;; These functions define states of the world ;;; as an abstract data type. (defun make-state (f w g c) (list f w g c)) (defun farmer-side ( state ) (nth 0 state)) (defun wolf-side ( state ) (nth 1 state)) (defun goat-side ( state ) (nth 2 state)) (defun cabbage-side ( state ) (nth 3 state)) ;;; The function "opposite" takes a side and returns ;;; the opposite side of the river. (defun opposite (side) (cond ((equal side 'e) 'w) ((equal side 'w) 'e))) ;;; Safe returns nil if a state is not safe; it returns ;;;the state unchanged if it is safe. (defun safe (state) (cond ((and(equal(goat-side state)(wolf-side state)) (not (equal (farmer-side state) (wolf-side state)))) nil) ((and (equal (goat-side state) (cabbageside state)) (not (equal (farmer-side state) (goat-side state)))) nil) (t state))) ;;; These functions define legal moves in the state space (defun farmer-takes-self (state) (safe (make-state (opposite (farmer-side state)) (wolf-side state) (goat-side state) (cabbage-side state)))) (defun farmer-takes-wolf (state) (cond ((equal (farmer-side state) (wolf-side state)) (safe (make-state (opposite (farmer-side state)) (opposite (wolf-side state)) (goat-side state) (cabbage-side state)))) (t nil))) (defun farmer-takes-goat (state) (cond ((equal (farmer-side state) (goat-side state)) (safe (make-state (opposite (farmer-side state)) (wolf-side state) (opposite (goat-side state)) (cabbage-side state)))) (t nil))) (defun farmer-takes-cabbage (state) (cond ((equal (farmer-side state) (cabbage-side state)) (safe (make-state (opposite (farmer-side state)) (wolf-side state) (goat-side state) (opposite (cabbage-side state))))) (t nil))) ;;; The recursive path algorithm searches the space in a depth first ;;; fashion. (defun path (state goal been-list) (cond ((null state) nil) ((equal state goal)(reverse (cons state been-list))) ((not(member state been-list :test #'equal)) (or (path(farmer-takes-self state)goal(cons state been-list)) (path(farmer-takes-wolf state)goal(cons state been-list)) (path(farmer-takes-goat state)goal(cons state been-list)) (path(farmer-takes-cabbage state)goal(cons state beenlist)))))) ;;; solve-fwgc initiates the search. (defun solve-fwgc (state goal) (path state goal nil)) THE STATE SPACE W W W W E W W W EE W W E W E W E W WE W W E W E W E W W W W W E E E W W E E W E W E E W W E W E E W W WE W W E E E W W E W W W E W E E E W E E E W E W W W E E E E E PATH = {(W W W W) (E W E W) (W W E W) (E E E W) (W E W W) (E E W E) (W E W E) (E E E E)} Breadth First Search (setq *moves* '(farmer-takes-self farmer-takes-wolf farmer-takes-goat farmer-takes-cabbage)) (defun run-breadth (start goal) (setq *open* (list start)) (setq *closed* nil) (setq *goal* goal) (breadth-first)) (defun breadth-first () (cond ((null *open*) nil) (t (let ((state (car *open*))) (cond ((equal state *goal*) 'success) (t (setq *closed* (cons state *closed*)) (setq *open*(append (cdr *open*) (generate-descendants state *moves*))) (breadth-first))))))) (defun generate-descendants (state moves) (cond ((null moves) nil) (t (let ((child (funcall (car moves) state)) (rest (generate-descendants state (cdr moves)))) (cond ((null child) rest) ((member child rest :test #'equal) rest) ((member child *open* :test #'equal) rest) ((member child *closed* :test #'equal) rest) (t (cons child rest))))))) (run-breadth ‘(w w w w) ‘(e e e e)) SUCCESS Depth First Search (defun depth-first () (cond ((null *open*) nil) (t (let ((state (car *open*))) (cond ((equal state *goal*) 'success) (t (setq *closed* (cons state *closed*)) (setq *open* (append (generate-descendants state *moves*)(cdr *open*))) (depth-first))))))) Breadth First Search With Parent information Attached (defun run-breadth (start goal moves) (declare (special *open*)) (declare (special *closed*)) (declare (special *goal*)) (setq *open* (list (build-record start nil))) (setq *closed* nil) (setq *goal* goal) (breadth-first moves)) ;;; These functions handle the creation and access of (state parent) ;;; pairs. (defun build-record (state parent) (list state parent)) (defun get-state (state-tuple) (nth 0 state-tuple)) (defun get-parent (state-tuple) (nth 1 state-tuple)) (defun retrieve-by-state (state list) (cond ((null list) nil) ((equal state (get-state (car list))) (car list)) (t (retrieve-by-state state (cdr list))))) (defun breadth-first (moves) (declare (special *open*)) (declare (special *closed*)) (declare (special *goal*)) (cond ((null *open*) nil) (t (let ((state (car *open*))) (setq *closed* (cons state *closed*)) (cond ((equal (get-state state) *goal*) (reverse (build-solution *goal*))) (t (setq *open* (append (cdr *open*) (generate-descendants (get-state state) moves))) (breadth-first moves))))))) (defun generate-descendants (state moves) (declare (special *open*)) (declare (special *closed*)) (cond ((null moves) nil) (t (let ((child (funcall (car moves) state)) (rest (generate-descendants state (cdr moves)))) (cond ((null child) rest) ((retrieve-by-state child rest) rest) ((retrieve-by-state child *open*) rest) ((retrieve-by-state child *closed*) rest) (t (cons (build-record child state) rest))))))) (defun build-solution (state) (declare (special *closed*)) (cond ((null state) nil) (t (cons state (build-solution (get-parent (retrieve-by-state state *closed*))))))) Best First Search (setq *moves* '(farmer-takes-self farmer-takes-wolf farmer-takes-goat farmer-takes-cabbage)) (defun heuristic (state) (heuristic-eval state *goal*)) (defun heuristic-eval (state goal) (cond ((null state) 0) ((equal (car state) (car goal)) (heuristic-eval (cdr state) (cdr goal))) (t (1+ (heuristic-eval (cdr state) (cdr goal)))))) (defun insert-by-weight (children sorted-list) (cond ((null children) sorted-list) (t (insert (car children) (insert-by-weight (cdr children) sorted-list))))) (defun insert (item sorted-list) (cond ((null sorted-list) (list item)) ((< (get-weight item) (get-weight (car sortedlist))) (cons item sorted-list)) (t (cons (car sorted-list) (insert item (cdr sortedlist)))))) ;;; These functions handle the creation and access of (state parent) ;;; pairs. (defun build-record (state parent depth weight) (list state parent depth weight)) (defun get-state (state-tuple) (nth 0 state-tuple)) (defun get-parent (state-tuple) (nth 1 state-tuple)) (defun get-depth (state-tuple) (nth 2 state-tuple)) (defun get-weight (state-tuple) (nth 3 state-tuple)) (defun retrieve-by-state (state list) (cond ((null list) nil) ((equal state (get-state (car list))) (car list)) (t (retrieve-by-state state (cdr list))))) (defun run-best (start goal) (setq *goal* goal) (setq *open* (list (build-record start nil 0 (heuristic start)))) (setq *closed* nil) (best-first)) (defun best-first () (print "open =") (print *open*) (print "closed =") (print *closed*) (cond ((null *open*) nil) (t (let ((state (car *open*))) (setq *closed* (cons state *closed*)) (cond ((equal (get-state state) *goal*) (buildsolution *goal*)) (t (setq *open* (insert-by-weight (generate-descendants (get-state state)(1+ (getdepth state)) *moves*)(cdr *open*))) (best-first))))))) (defun generate-descendants (state depth moves) (cond ((null moves) nil) (t (let ((child (funcall (car moves) state)) (rest (generate-descendants state depth (cdr moves)))) (cond ((null child) rest) ((retrieve-by-state child rest) rest) ((retrieve-by-state child *open*) rest) ((retrieve-by-state child *closed*) rest) (t (cons (build-record child state depth (+ depth (heuristic child))) rest))))))) (defun build-solution (state) (cond ((null state) nil) (t (cons state (build-solution (get-parent (retrieve-by-state state *closed*)))))))