Universitetet i Linköping Institutionen för datavetenskap

advertisement
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
Test of equality
TDDC65 Artificial intelligence and Lisp
Lecture 2 in Lisp
Recursion, symbols and lists
(chapter 4, 5, 6 Haraldssons book)
list functions
local variables and local functions
recursion over sequences
* patterns
* recursive / iterative process
* double recursion
* back tracking
(= 5 5)
- numbers
(eq 'a 'a)
- symbols (or pointers)
(eql 5 5)
- atoms
(eql #\a #\a)
(eql 'a 'a)
(equal '(a b c) '(a b c))
- lists
Test of data types
the function cons
graphical representation of lists
the list as a binary tree
traversing formulas
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
(numberp 5) - number?
(symbolp 'a) - symbol?
(atom 5)
- atom? = not a list?
(atom 'a)
(listp '(a b c)) - list?
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
To create lists
The primitive
(cons 'a '(b c)) => (a b c)
Common Lisp functions for lists
Some of them:
Is an element on a list?
Concatenate 2 (or more) lists
(append '(a b) '(x y)) => (a b x y)
Create a list of a fixed number of elements
(list 'a (1+ 4) (first '(b c))) => (a 5 b)
Constant list
'(a b c d) or (quote (a b c d))
Observe the difference. What is?
(cons '(1 2) '(a b)) => ?
(append '(1 2) '(a b)) => ?
(member 'x '(a b x c)) => true
Remove all occurrences of an element
(remove 'q '(a b q r q)) => (a b r)
Reverse the elements on a list
(reverse '(a b c)) => (c b a)
Replace all occurrences of an element
(subst 'new-q 'q '(a q (b q)))
=> (a new-q (b new-q))
Find the last part of a list
(last '(ett två tre)) => (tre)
Find the n+1 element
(nth '(a b c d) 2) => c
(list '(1 2) '(a b)) => ?
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
How to add a new last element?
Local variables
Put five last on the list (one two three four).
Example:
(append '(one two three four) (list 'five))
=> (one two three four five)
(let ((var expr) (var expr) ...)
expr)
Avoid double calculations:
Define a function add-to-the-end
(defun add-to-the-end (e l)
(append l (list e)))
What happens here?
(setq number-list '(one two three four))
(add-to-the-end 'five number-list)
=> (one two three four five)
number-list
=> ?
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
g(x) = sin(f(x)) + cos(f(x))
(defun g (x)
(let ((f-value (f x)))
(+ (sin f-value) (cos f-value)))
After the let-expression the binding disappear between the variable and value.
Introduce a local name for a value:
(let ((vocals ’(a e i o u å ä ö)))
.... (member (first l) vocals) ... )
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
Local functions
(labels ((fn (argument) body))
(fn (argument) body))
...)
expression)
Example: f(x,y) = x!/y2
(defun f (x y)
(labels ((square (n) (* n n))
(fak (n)
(if (= n 0)
1
(* n (fak (- n 1))))))
(/ (fak x) (square y))))
The function definitions are only valid
inside f!
Example: When we have iterative process the recursive function is defined locally.
(defun fak (n) (fak-iter n 1))
(defun fak-iter (n res)
(if (= n 0)
res
(fak-iter (- n 1) (* n res))))
(defun fak (n)
(labels
((fak-iter (n res)
(if (= n 0)
res
(fak-iter (- n 1) (* n res))))
)
(fak-iter n 1)))
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
Sequential processing of lists
recursive process
Sequential processing of lists
iterative process
(defun fn (l) (fn-iter l ”init-value”))
(defun fn-sekv (l)
(cond
((endp l) “init-value”)
(”other condition” ”expression”)
(t (”operation”
(first l)
(fn-sekv (rest l)) )))
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
(defun fn-iter (l res)
(cond
((endp l) res)
(”other condition” ”expression”)
(t (fn-iter
(rest l)
(”operation” (first l) res)) )))
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
Example
iterative process:
recursive process:
Replace the first occurrence of a given element
(change 'karl ’kalle '(lisa per kalle stina))
=> (lisa per karl stina)
(defun change (new old l)
(cond ((endp l) ’())
((eq old (first l))
(cons new (rest l)))
(t (cons (first l)
(change new
old
(rest l))) )))
(defun change (new old l)
(change-iter new old l ’()))
(defun change-iter (n g l res)
(cond ((endp l) res)
((eq g (first l))
(append res (cons n (rest l))))
(t (change-iter
n g (rest l)
(add-to-the-end (first l) res)))))
Why add-to-the-end instead of cons?
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
The substitution model for the two solutions:
Double recursion
Lists with lists as elements
recursive process:
(change 'karl ’kalle '(lisa per kalle stina))
-> (cons ’lisa (change ’karl ’kalle ’(per kalle stina))
-> (cons ’lisa (cons ’per (change ’karl ’kalle
’(kalle stina)))
-> (cons ’lisa (cons ’per (cons ’karl ’(stina))))
-> (cons ’lisa (cons ’per ’(karl stina)))
-> (cons ’lisa ’(per karl stina))
=> (lisa per karl stina)
Pattern for sequences:
(defun fn (l)
(cond
((endp l) “init-value”)
((atom (first l))
(“operation”
(first l)
(fn (rest l))))
(t (“operation”
(fn (first l))
(fn (rest l)))) ))
iterative process:
(change 'karl ’kalle '(lisa per kalle stina))
-> (ch-i ’karl ’kalle ’(lisa per kalle stina) ’())
-> (ch-i ’karl ’kalle ’(per kalle stina) ’(lisa))
-> (ch-i ’karl ’kalle ’(kalle stina) ’(lisa per))
-> (ch-i ’karl ’kalle (append ’(lisa per)
(cons ’karl ’(stina))))
=> (lisa per karl stina)
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
Total number of elements
(defun symbols-in-seq (l)
(cond
((endp l) 0)
((atom (first l))
(+ 1 (symbols-in-seq (rest l))))
(t (+
(symbols-in-seq (first l))
(symbols-in-seq (rest l))) )))
(symbols-in-seq '(a (b c (d e)) f))
=> 6
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
Remove all occurrences of a symbol on all
levels
(defun my-all-remove (x l)
(cond
((endp l) ’())
((atom (first l))
(if (eq x (first l))
(my-all-remove x (rest l))
(cons
(first l)
(my-all-remove x (rest l))))
(t (cons
(my-all-remove x (first l))
(my-all-remove x (rest l))) )))
(my-all-remove 'q '(a q (b q (q)) c))
=> (a (b nil) c)
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
Back tracking
Is a given element somewhere in a list?
(exist? 'q '(a (b q) c)) => t
(defun exist? (x l)
(cond ((endp l) nil)
((atom (first l))
(if (eq x (first l))
t
(exist? x (rest l))))
(t (or (exist? x (first l))
(exist? x (rest l))) )))
Some problems are of the nature that you can not directly say if you have reached the right element or
not. You must go on.
Typical in search problems you must handle back
tracking. Search one alternative, if it fails come back
and try another alternative. Lab 2 and 3 use this concept.
Here we will solve the following problem:
Find the element after the last occurrence of a given
element. We assume that the given element is not
last in the list.
(find-after ’x ’(a b x c))
=> c
(find-after ’x ’(a b x c x d x e))
=> e
(find-after ’x ’(a b c))
=> element-not-on-list
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
(defun find-after (x l)
(cond
((endp l) ’element-not-on-list)
((eq x (first l)) ; the element is found
(let ((next-value (find-after x (rest l))))
; check further
(if (eq next-value
’element-not-on-list)
(second l)
next-value)))
(t (find-after x (rest l)))))
The function cons
dotted pair:
(cons ’a ’b)
=> (a . b)
dotted list:
(cons ’x (cons ’y ’z))
=> (x y . z)
association list:
((ett . one) (två . two) (tre . three))
Observe that all of these expressions describes the same list:
(x y z) = (x y z . nil) = (x y . (z . nil)) =
(x . (y . (z . nil)))
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
The list seen as a binary tree
The list seen as a binary tree
Pattern - binary tree:
(defun fn (bt)
(if (atom bt) <- leaf?
“processing of the leaf ”
(“operation”
(fn (car bt))
(fn (cdr bt)))))
pattern - binary tree
- nil a special case:
(defun fn (bt)
(cond
((eq bt nil) “value”)
((atom bt) “processing of the leaf”)
(t (“operation”
(fn (car bt))
(fn (cdr bt)))))
Observe: Here I use car and cdr instead
of first and rest. (Better with primitives
left and right)
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
Number of elements (as leaves)
Here is nil a leaf, it will be counted.
(defun count-leaves (bt)
(if (atom bt)
1
(+ (count-leaves (car bt))
(count-leaves (cdr bt)) )))
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
Observations
Sequence solution:
3 cases - end of list
- first element is an atom
- first element is a list
Binary tree solution
Here is nil not a leaf
2 cases - atom (the leaf)
- list (intern nod in the tree)
(defun count-leaves (bt)
(cond
((eq bt nil) 0)
((atom bt) 1)
(t (+ (count-leaves (car bt))
(count-leaves (cdr bt)) )))
Observe: The binary tree algorithm is
more general, it includes the sequential
algorithm.
But, of course the problems nature
gives what solution to use.
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
Universitetet i Linköping
Institutionen för datavetenskap
Anders Haraldsson
An arithmetic formula as a binary tree.
*
+
2
/
4
8
3
2
We represent the binary tree as a list
with the following structure:
(left-tree operator right-tree)
Define a function to calculate its value
(value 3) => 3
(value ’((2 + 4) * ((8 - 2) / 3))) => 12
(defun value (expr)
(cond
((number? expr) expr)
((eq (operator expr) ’+)
(+ (value (arg1 expr))
(value (arg2 expr))))
((eq (operator expr) ’-)
(- (value (arg1 expr))
(value (arg2 expr))))
((eq (operator expr) ’*)
(* ... ...))
((eq (operator expr) ’/)
(/ ... ...))
(t (error ... error message...))))
(defun number? (expr) (numberp expr))
(defun arg1 (expr) (first expr))
(defun arg2 (expr) (third expr)
(defun operator (expr) (second expr))
Download