Lists in Lisp and Scheme
Total Page:16
File Type:pdf, Size:1020Kb
Lists in Lisp and Scheme • Lists are Lisp’s fundamental data structures • However, it is not the only data structure Lists in Lisp – There are arrays, characters, strings, etc. – Common Lisp has moved on from being merely a LISt Processor and Scheme • However, to understand Lisp and Scheme you must understand lists – common funcAons on them – how to build other useful data structures with them In the beginning was the cons (or pair) Pairs nil • What cons really does is combines two objects into a a two-part object called a cons in Lisp and a pair in • Lists in Lisp and Scheme are defined as Scheme • Conceptually, a cons is a pair of pointers -- the first is pairs the car, and the second is the cdr • Any non empty list can be considered as a • Conses provide a convenient representaAon for pairs pair of the first element and the rest of of any type • The two halves of a cons can point to any kind of the list object, including conses • We use one half of the cons to point to • This is the mechanism for building lists the first element of the list, and the other • (pair? ‘(1 2) ) => #t to point to the rest of the list (which is a nil either another cons or nil) 1 Box nota:on Z What sort of list is this? null Where null = ‘( ) null a a d A one element list (a) null null b c a b c > (set! z (list ‘a (list ‘b ‘c) ‘d)) (car (cdr z)) A list of 3 elements (a b c) (A (B C) D) ?? Pair? Equality • Each Ame you call cons, Scheme allocates a new memory with room for two pointers • The funcAon pair? returns true if its • If we call cons twice with the same arguments, we argument is a cons (pair? = consp in CL) get back two values that look the same, but are in • fact disAnct objects: So list? could be defined: > (define l1 (cons 'a ‘())) (define (list? x) (or (null? x) (pair? x))) (A) (define l2 (cons 'a nil))) • Since everything that is not a pair is an (A) atom, the predicate atom could be defined: ( eq? l1 l2) # f (define (atom? x) (not (pair? x))) (equal? l1 l2) # t (and ( eq? (car l1)(car l2)) (eq? (cdr l1)(cdr l2))) # t 2 Equal? Equal? • We also need to be able to ask whether two lists (define (equal? x y) have the same elements • Scheme provides an equality predicate for this, equal ; this is ~ how equal? could be defined • Eq? returns true iff its arguments are the same (cond ((number? x) (= x y)) object, and ((not (pair? x)) (eq? x y)) • Equal?, more or less, returns true if its arguments ((not (pair? y)) #f) would print the same. > (equal? l1 l2) ((equal (car x) (car y)) T (equal (cdr x) (cdr y))))) Note: if x and y are eq?, they are also equal? Does Lisp have pointers? Does Scheme have pointers? • A secrets to understanding Lisp is to realiZe that variables have values in the same way that • The locaAon in memory associated with the lists have elements variable x does not contain the list itself, but a • As pairs have pointers to their elements, pointer to it. variables have pointers to their values • • What happens, for example, when we set two When we assign the same value to y, Sccheme variables to the same list: copies the pointer, not the list. > (set! x ‘(a b c)) • Therefore, what would the value of (A B C) This is just like > (eq? x y) > (set! y x) in Java (A B C) be, #t or #f? 3 Building Lists LISP’s Copy-list • copy-list takes a list and returns a copy of it Copy-list is a built in funcAon in Lisp but could be • The new list has the same elements, but defined in Scheme as follows contained in new pairs > (set! x ‘(a b c)) (define (copy-list s) (A B C) (if (pair? s) > (set! y (copy-list x)) (A B C) (cons (copy-list (car s)) • Spend a few minutes to draw a box diagram (copy-list (cdr s))) of x and y to show where the pointers point s)) Append append • The Scheme/Lisp funcon append returns the concatenaAon of any number of lists: • The two argument version of append could > (append ‘(a b) ‘(c d) ‘(e)) have been defined like this. (a b c d e) (define (append2 s1 s2) • Append copies all the arguments except the (if (null? s1) last s2 • If it didn’t copy all but the last argument, (cons (car s1) then it would have to modify the lists (append2 (cdr s1) s2)))) passed as arguments • • Such side effects are very undesirable, NoAce how it ends up copying the top level list especially in funcAonal languages. structure of it’s first argument. 4 List access func:ons Lisp’s nth and nthcdr (define (nth n l) • To find the element at a given posiAon in a (cond ((null? l) ‘() ) list use the funcAon list-ref (nth in CL). ((= n 0) (car l)) (list-ref ‘(a b c) 0) (#t (nth (- n 1) (cdr l))))) a • and to find the nth cdr, use list-tail (nthcdr (define (nthcdr n l) in CL). (cond ((null? l) ‘() ) > (list-tail ‘(a b c) 2) ((= n 0) (cdr l)) (#t (nthcdr (- n 1) (cdr l))))) (C) • Both funcAons are Zero indexed. Accessing lists Member • The built-in Scheme funcon last returns the last element • Member returns true, but instead of simply in a list returning t, its returns the part of the list (define (last l) beginning with the object it was looking for. (if (null? (cdr l)) (car l) > (member ‘b ‘(a b c)) (last (cdr l)))) (b c) (last ‘(a b c)) • c member compares objects using equal? • Note: in CL, last returns the last cons cell (aka pair) • There are versions that use eq? and eqv? • We also have: first, second, third, and CxR, where x is a And that take an arbitrary funcon string of up to four as or ds. – E.g., cadr, caddr, cddr, cdadr, … 5 Defining member Memf • If we want to find an element saAsfying an (define member (thing list) arbitrary predicate we use the funcAon (cond ((null? List) #f) memf: > (memf odd? ‘(2 3 4)) ((equal? thing (first list)) list) (3 4) (#t (member thing (rest list))))) • Which could be defined like: (define (memf f l) (cond ((null? l) #f) ((f (car l)) l) (#t (memf f (cdr l))))) Doed Lists • A pair that isn’t a proper list is called a • The kind of lists that can be built by calling list are doced pair more precisely known as proper lists A proper list is either the empty list, or a pair whose cdr is a • However, remember that a doced pair isn’t proper list really a list at all • Pairs are not just for building lists -- whenever you need a structure with two fields you can use a pair • It is a just a two part data structure. • Use car to reference the 1st field and cdr for the 2nd > (set! pair (cons ‘a ‘b)) (a . b) • Because this pair is not a proper list, it’s displayed in dot notaCon In dot notaAon the car and cdr of each pair are a b shown separated by a period (a . b) 6 .