AI - Lisp / Lab 2 - Higher order functions and pattern matching 7 Lab 2 Higher order functions and pattern matching 2.1 HIGHER ORDER FUNCTIONS A higher order function is a function which takes another function as argument or returns a function as value. Exercise 2.1a Define a function acc1st with arguments n and fn, where n should be a positive integer and fn a numeric function with one argument. The function acc1st shall accumulate the results from fn applied on the n first integer [1..n]: acc1st ( n, fn ) = n ∑i = 1 fn ( i ) (acc1st 10 #'-) => -55 ; -1 + -2 + -3 + -4 + -5 + -6 + -7 + -8 + -9 + -10 (acc1st 5 #'(lambda (x) (* x x))) => 55 ; 12+22+32+42+52 Exercise 2.1b. Define a function filter with two arguments, a predicate function (given a truth value as result) pred-fn with one argument. The function works as a filter, which is applied on every element in a straight list. The function filter shall return a new list with the filtered elements: (filter #'numberp '(a b 4 c 9 3 d)) => (4 9 3) (filter #'(lambda (x) (or (eq x 'a) (eq x 'b))) '(a b c d a d b c c b a)) => (a b a b b a) ASSIGNMENT 2A - PASCAL’S TRIANGLE Define a higher order function generate-list, which creates a list with n elements which starts with a given start element and the rest of the elements will be computed by a given function. (generate-list start-element function-to-compute-next-element number-of-elements) (generate-list 10 #’(lambda (n) (- n 2)) 5) => (10 8 6 4 2) ; decrease next element with 2 (generate-list ’(a b c d e f) #’rest 3) => ((a b c d e f) (b c d e f) (c d e f)) 8 AI - Lisp / Lab 2 - Higher order functions and pattern matching Use this higher order function to define a function pascal, which computes the Pascal’s triangle which stores the binomial coefficients. Pascal’s triangle for 6 rows is as follows: 1 1 1 1 1 1 1 2 3 4 5 1 3 6 10 1 4 10 1 5 1 The numbers in the next row are constructed from the previous ones by adding the two numbers on the row over it. A row starts and ends with the value 1. Represent the triangle as a list of lists. (pascal 6) => ((1) (1 1) (1 2 1) (1 3 3 1) (1 4 6 4 1) (1 5 10 10 5 1)) 2.2 PATTERN MATCHING In pattern matching we want to see if a pattern matches data of some kind. We will here match lists and we introduce here two pattern symbols & for matching one arbitrary element and -- for matching a segment consisting of zero, one or more elements. pattern list result (a & b) (a & b) (a & b) (a & b) (a & b) (a x b) (a y b) (a b) (a b c) (a x y b) match match no match no match no match (a -- b) (a -- b) (a -- b) (a -- b) (a b) (a x b) (a x y b) (a x b c) match match match no match (& b -- c & d) (a b x y c z d) match (a -- b c) (a x b y b c) match A simple pattern matcher is the following: (defun patmatch (l pat) (cond ((endp pat) (endp l)) ; end of list and pattern? ((eq (first pat) '--) ; segment pattern? (cond ((patmatch l (rest pat)) t) ; does the rest match? ((endp l) nil) ; failed, the segment pattern ; match the rest of the list (t (patmatch (rest l) pat)))) ; let the segment pattern ; take the next element ((endp l) nil) ; no more elements to match against ((eq (first pat) '&) ; match an arbitrary element (patmatch (rest l) (rest pat))) ((eql (first pat) (first l)) ; exact match (patmatch (rest l) (rest pat))) (t nil)))) ; no match at all, failed AI - Lisp / Lab 2 - Higher order functions and pattern matching 9 Exercise 2.2a. Implement the patmatch function. Trace it and run a number of test examples. The difficult part to understand is the matching of the segment pattern and how it does "back-tracking". Test the above examples. Check also the termination conditions. Does this match? (patmatch ’(--) ’()) (patmatch ’(-- -- --) ’()) Test also the following example: (patmatch ’(a x b y b c) ’(a -- b c)) Here we start to match the element a. The the segment pattern will be in action. First try to match the rest of the pattern with the list. Does (x b y b c) match the pattern (b c). No, x does not match b. Back up and let the segment pattern match one more element, now the element x. Match the rest of the list (b y b c) with the rest of the pattern (b c). The first element matches, but then it does not match. Back up and let the segment also include b. We go on and also let y be included in the segment pattern. The the rest of the list (b c) matches the rest of the pattern (b c). The final result is that it matches. Test it and follow it by trace. ASSIGNMENT 2B - PATTERN MATCHING IN A SMALL DATA BASE We will here create a small data base to store for example information about books. We represent the data base as a list of records, where every record is a list of some kind of information. For simplicity this information may be put in some order in the record. A data base of books could look like this: ( ((author (anders haraldsson)) (title (programmering i lisp)) (year 1993) (place (room (left 4)))) ((author (anders haraldsson)) (title (programmering i pascal)) (year 1979) (place (room (left 2)))) ((author (nils nilsson)) (title (artificial intelligence)) (year 1999) (place (library (pu 1573)))) ... ) We need a function find-books which takes a pattern and returns all books fulfilling this pattern. Find all books by haraldsson: (find-books ’((author (& haraldsson)) --)) => (((author (anders haraldsson)) (title (programmering i lisp)) (year 1993) (place (room (left 4)))) ((author (anders haraldsson)) (title (programmering i pascal)) (year 1979) (place (room (left 2)))) ) Find all books with a title containing programmering? (find-books ’(-- (title (-- programmering --)) --)) => (((author (anders haraldsson)) (title (programmering i lisp)) (year 1993) (place (room (left 4)))) ((author (anders haraldsson)) (title (programmering i pascal)) (year 1979) (place (room (left 2))))) What we now need is a pattern matcher which takes a pattern and a list of an arbitrary structure, not only a straight list as the function patmatch handles above. Extend patmatch so it can handle arbitrary lists (dotted pair is not necessary). The pattern symbol & will in this case match a lit element, either a symbol or a list. We will also introduce more pattern symbols. We want to match numbers in a given interval and we want to write (< n) and (> n). We will also have a pattern (not pattern) to say that we have a pattern which we will not match. Observe that the not symbol takes a pattern, so we can not use a symbol here. 10 AI - Lisp / Lab 2 - Higher order functions and pattern matching Find all books written after 1985 by anders haraldsson? (find-books ’((author (anders haraldsson)) & (year (> 1985)) --)) => (((author (anders haraldsson)) (title (programmering i lisp)) (year 1993) (place (room (left 4))))) Find all books by anders haraldsson with a title which does not end with lisp? (find-books ’((author (anders haraldsson)) (title (not (-- lisp))) --))) => (((author (anders haraldsson)) (title (programmering i pascal)) (year 1979) (place (room (left 2)))))