Lists in Lisp nd Scheme Lists in Lisp nd Scheme Lists re Lisp s fundmentl dt structures, ut there re others Arrys, chrcters, strings, etc. Common Lisp hs moved on from eing merely LISt Processor However, to understnd Lisp nd Scheme you must understnd lists common func?ons on them how to uild other useful dt structures with them Lisp Lists Lists in Lisp nd its descendnts re very simple linked lists Represented s liner chin of nodes Ech node hs (pointer to) vlue (cr of list) nd pointer to the next node (cdr of list) Lst node s cdr pointer is to null Lists re immutle in Scheme Typicl ccess phern is to trverse the list from its hed processing ech node In the eginning ws the cons (or pir) Wht cons relly does is comines two ojects into two- prt oject clled cons in Lisp nd pir in Scheme Conceptully, cons is pir of pointers - - the first is the cr, nd the second is the cdr Conses provide convenient represent?on for pirs of ny type The two hlves of cons cn point to ny kind of oject, including conses This is the mechnism for uilding lists (pir? (1 2) ) => #t null 1
Pirs Lists in Lisp nd Scheme re defined s pirs Any non empty list cn e considered s pir of the first element nd the rest of the list We use one hlf of cons cell to point to the first element of the list, nd the other to point to the rest of the list (which is either nother cons or nil) () ( c) Box nd pointer not:on A one element list () c A list of three elements ( c) null Common nottion: use digonl line in cdr prt of cons cell for pointer to null Z Wht sort of list is this? Pir? Z is list with three elements: (i) the tom, (ii) list of two elements, & c nd (iii) the tom d. c > (define Z (list (list c) d)) > Z ( ( c) d) > (cr (cdr z))?? d The func?on pir? returns true if its rgument is cons cell The equivlent func?on in CL is consp So list? could e defined: (define (list? x) (or (null? x) (pir? x))) Since everything tht is not pir is n tom, the predicte tom could e defined: (define (tom? x) (not (pir? x))) 2
Ech?me you cll cons, Scheme lloctes new cons cell from memory with room for two pointers If we cll cons twice with the sme rgs, we get two vlues tht look the sme, ut re dis?nct ojects Equlity (define L1 (cons ' null)) L1 (A) (define L2 (cons ' null))) L2 (A) (eq? L1 L2) #f (equl? L1 L2) #t (nd (eq? (cr L1)(cr L2)) (eq? (cdr L1)(cdr L2))) #t Equl? Do two lists hve the sme elements? Scheme provides predicte equl? tht is like Jv s equl method Eq? returns true iff its rguments re the sme oject, nd Equl?, more or less, returns true if its rguments would print the sme. > (equl? L1 L2) #t Note: (eq? x y) implies (equl? x y) Equl? (define (myequl? x y) ; this is ~ how equl? could e defined (cond ((numer? x) (= x y)) ((not (pir? x)) (eq? x y)) ((not (pir? y)) #f) ((myequl (cr x) (cr y)) (myequl? (cdr x) (cdr y))) (#t #f))) Use trce to see how it works > (require rcket/trce) > (trce myequl?) > (myequl? '( c) '( c)) >(myequl? ( c) ( c)) > (myequl? ) < #t >(myequl? ( c) ( c)) > (myequl? ) < #t >(myequl? (c) (c)) > (myequl? c c) < #t >(myequl? () ()) <#t Trce is deugging pckge showing wht rgs userdefined function is clled with nd wht it returns The require function lods the pckge if needed #t 3
Does Lisp hve pointers? Vriles point to their vlues A secret to understnding Lisp is to relize tht vriles hve vlues in the sme wy tht lists hve elements As pirs hve pointers to their elements, vriles hve pointers to their vlues Scheme mintins dt structure represen?ng the mpping of vriles to their current vlues. > (define x ( )) > x ( ) > (define y x) y ( ) environment VAR x y VALUE Vriles point to their vlues Does Scheme hve pointers? > (define x ( )) > x ( ) > (define y x) y ( ) > (set! y (1 2) > y (1 2) environment VAR x y VALUE 1 2 The loc?on in memory ssocited with the vrile x does not contin the list itself, ut pointer to it. When we ssign the sme vlue to y, Scheme copies the pointer, not the list. Therefore, wht would the vlue of > (eq? x y) e, #t or #f? 4
Length is simple func:on on Lists The uilt- in func?on length tkes list nd returns the numer of its top- level elements Here s how we could implement it (define (length L) (if (null? L) 0 (+ 1 (length (cdr L)))) As typicl in dynmiclly typed lnguges (e.g., Python), we do miniml type checking The underlying interpreter does it for us Get run-?me error if we pply length to non- list Building Lists list- copy tkes list nd returns copy of it The new list hs the sme elements, ut contined in new pirs > (set! x ( c)) ( c) > (set! y (list- copy x)) ( c) Spend few minutes to drw ox digrm of x nd y to show where the pointers point Copy- list List- copy is Lisp uilt- in (s copy- list) tht could e defined in Scheme s: (define (list- copy s) (if (pir? s) (cons (list- copy (cr s)) (list- copy (cdr s))) s)) Given non- tomic s- expression, it mkes nd returns complete copy (e.g., not just the top- level spine) ppend returns the concten?on of ny numer of lists Append copies its rguments except the lst If not, it would hve to modify the lists Such side effects re undesirle in func?onl lnguges Append >(ppend ( ) (c d)) ( c d) > (ppend (()()) (((c)))) (() () ((c))) > (ppend ( ) (c d) (e)) ( c d e) >(ppend ( ) ()) ( ) >(ppend ( )) ( ) >(ppend) () 5
Append The two rgument version of ppend could e defined like this (define (ppend2 s1 s2) (if (null? s1) s2 (cons (cr s1) (ppend2 (cdr s1) s2)))) No?ce how it ends up copying the top level list structure of its first rgument > (lod "ppend2.ss") > (define L1 '(1 2)) > (define L2 '( )) > (define L3 (ppend2 L1 L2)) > L3 (1 2 ) > L1 (1 2) > L2 ( ) Visulizing Append > (require rcket/trce) > (trce ppend2) > (ppend2 L1 L2) >(ppend2 (1 2) ( )) > (ppend2 (2) ( )) > >(ppend2 () ( )) < <( ) < (2 ) <(1 2 ) (1 2 ) Append does not modify its rguments. It mkes copies of ll of the lists sve the lst. > (lod "ppend2.ss") > (define L1 '(1 2)) > (define L2 '( )) > (define L3 (ppend2 L1 L2)) > L3 (1 2 ) > L1 (1 2) > L2 ( ) > (eq? (cdr (cdr L3) L2) #f Visulizing Append environment VAR L2 L1 L3 VALUE 1 2 Append2 copies the top level of its first list rgument, L1 List ccess func:ons To find the element t given posi?on in list use the func?on list- ref (nth in CL) > (list- ref ( c) 0) To find the nth cdr, use list- til (nthcdr in CL) > (list- til ( c) 2) (c) Both func?ons re zero indexed 6
> (define L '( c d)) > (list- ref L 2) c > (list- ref L 0) > (list- ref L - 1) list- ref: expects type <non- neg?ve exct integer> s 2nd rg, given: - 1; other rguments were: ( c d) > (list- ref L 4) list- ref: index 4 too lrge for list: ( c d) List- ref nd list- til > (list- til L 0) ( c d) > (list- til L 2) (c d) > (list- til L 4) () > (list- til L 5) list- til: index 5 too lrge for list: ( c d) Defining Scheme s list- ref & list- til (define (mylist- ref l n) (cond ((< n 0) (error...)) ((not (pir? l)) (error...)) ((= n 0) (cr l)) (#t (mylist- ref (cdr l) (- n 1))))) (define (mylist- til l n) (cond ((< n 0) (error...)) ((not (pir? l)) (error...)) ((= n 0) (cdr l)) (#t (mylist- ref (cdr l) (- n 1))))) Accessing lists Scheme s lst returns the lst element in list > (define (lst l) (if (null? (cdr l)) (cr l) (lst (cdr l)))) (lst ( c)) c Note: in CL, lst returns the lst cons cell (k pir) We lso hve: first, second, third, nd CxR, where x is string of up to four s or ds. E.g., cdr, cddr, cddr, cddr, Memer Memer returns true, ut insted of simply returning t, its returns the prt of the list eginning with the oject it ws looking for. > (memer ( c)) ( c) memer compres ojects using equl? There re versions tht use eq? nd eqv? And tht tke n ritrry funcgon 7
Defining memer (define (memer X L) (cond ((null? L) #f) ((equl? X (cr L)) L) (#t (memer X (cdr L))))) Memf If we wnt to find n element s?sfying n ritrry predicte we use the func?on memf: > (memf odd? (2 3 4)) (3 4) Which could e defined like: (define (memf f l) (cond ((null? l) #f) ((f (cr l)) l) (#t (memf f (cdr l))))) DoQed pirs nd lists Lists uilt y clling list re known s proper lists; they lwys end with pointer to null A proper list is either the empty list, or pir whose cdr is proper list Pirs ren t just for uilding lists, if you need structure with two fields, you cn use pir Use cr to get the 1st field nd cdr for the 2nd > (define the_pir (cons )) (. ) Becuse this pir is not proper list, it s displyed in dot notgon In dot not?on the cr nd cdr of ech pir re shown seprted y period DoQed pirs nd lists A pir tht isn t proper list is clled dohed pir Rememer tht dohed pir isn t relly list t ll, It s just (. ) two prt dt structure Doted pirs nd lists tht end with dohed pir re not used very onen If you produce one for 331 code, you ve proly mde n error 8
Conclusion Simple linked lists were the only dt structure in erly Lisps From them you cn uild most other dt structures though efficiency my e low Its s?ll the most used dt tructure in Lisp nd Scheme Simple, elegnt, less is more Recursion is the nturl wy to process lists 9