LISP - computer

advertisement
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*)))))))
Download