Lists in Lisp and Scheme

Lists in Lisp and Scheme

Lists in Lisp and Scheme Lisp Lists • Lists are Lisp’s fundamental data structures, • Lists in Lisp and its descendants are very but there are others Lists in Lisp simple linked lists – Arrays, characters, strings, etc. – Represented as a linear chain of nodes – Common Lisp has moved on from being • Each node has a (pointer to) a value (car of merely a LISt Processor and Scheme list) and a pointer to the next node (cdr of list) • However, to understand Lisp and Scheme – Last node’s cdr pointer is to null you must understand lists • Lists are immutable in Scheme – common functions on them • Typical access pattern is to traverse the list a – how to build other useful data structures from its head processing each node with them In the beginning was the cons (or pair) Pairs Box and pointer notation • What cons really does is combines two objects into a a Common notation: two-part object called a cons in Lisp and a pair in use diagonal line in • Lists in Lisp and Scheme are defined as (a) cdr part of a cons Scheme cell for a pointer to • Conceptually, a cons is a pair of pointers -- the first is pairs null a a null the car, and the second is the cdr • Any non empty list can be considered as a • Conses provide a convenient representation for pairs A one element list (a) of any type pair of the first element and the rest of • the list The two halves of a cons can point to any kind of (a b c) object, including conses • We use one half of a cons cell to point to • This is the mechanism for building lists the first element of the list, and the other • (pair? ‘(1 2) ) => #t a b c to point to the rest of the list (which is a null either another cons or nil) A list of three elements (a b c) 1 What sort of list is this? Z Pair? Equality • Each time you call (define L1 (cons 'a null)) • The function pair? returns true if its cons, Scheme L1 allocates a new (A) argument is a cons cell (define L2 (cons 'a null))) a d cons cell from • The equivalent function in CL is consp memory with room L2 • So list? could be defined: for two pointers (A) (eq? L1 L2) (define (list? x) (or (null? x) (pair? x))) • If we call cons twice #f with the same args, b c • Since everything that is not a pair is an (equal? L1 L2) we get two values #t Z is a list with three > (define Z (list ‘a (list ‘b ‘c) ‘d)) atom, the predicate atom could be defined: elements: (i) the atom a, > Z that look the same, (and (eq? (car L1)(car L2)) (ii) a list of two elements, (a (b c) d) (define (atom? x) (not (pair? x))) but are distinct (eq? (cdr L1)(cdr L2))) b & c and (iii) the atom d. > (car (cdr z)) objects #t ?? Equal? Equal? Use trace to see how it works • Do two lists have the same elements? (define (myequal? x y) > (require racket/trace) >(myequal? (c) (c)) • Scheme provides a predicate equal? that is like > (trace myequal?) > (myequal? c c) Java’s equal method ; this is how equal? could be defined > ( myequal ? '(a b c) '(a b c)) < #t • eq? returns true iff its arguments are the same (cond ((and (number? x) (number? y))(= x y)) >(myequal? (a b c) (a b c)) >(myequal? () ()) > (myequal? a a) <#t object, and ((and (string? x) (string? y)) (string=? x y)) < #t #t • equal?, more or less, returns true if its ((not (pair? x)) (eq? x y)) >(myequal? (b c) (b c)) arguments would print the same. ((not (pair? y)) #f) > (myequal? b b) > (equal? L1 L2) ((myequal? (car x) (car y)) < #t #t (myequal? (cdr x) (cdr y))) • Trace is a debugging package showing what args a user- • Note: (eq? x y) implies (equal? x y) defined function is called with and what it returns (#t #f))) • The require function loads the package if needed 2 Does Lisp have pointers? Variables point to their values Does Scheme have pointers? • A secret to understanding Lisp is to realize that > (define x ‘(a b)) environment • variables have values in the same way that lists The location in memory associated with the > x VAR VALUE have elements variable x does not contain the list itself, but a (a b) … a b pointer to it. • As pairs have pointers to their elements, > (define y x) • variables have pointers to their values x When we assign the same value to y, Scheme y copies the pointer, not the list. • Scheme maintains a data structure … (a b) • Therefore, what would the value of representing the mapping of variables to their y > (eq? x y) current values. … be, #t or #f? Variables point to their values Variables point to their values Length is a simple function on Lists > (define x ‘(a b)) environment > (define x ‘(a b)) environment • The built-in function length takes a list and > x VAR VALUE > x VAR VALUE returns the number of its top-level elements (a b) … a b (a b) … a b • Here’s how we could implement it > (define y x) x > (define y x) x (define (length L) y y (if (null? L) 0 (+ 1 (length (cdr L)))) (a b) … (a b) … 1 2 • As typical in dynamically typed languages y > (set! y ‘(1 2)) y (e.g., Python), we do minimal type checking … > y … – The underlying interpreter does it for us (1 2) – Get run-time error if we apply length to a non-list 3 Building Lists Copy-list Append • append returns the • >(append ‘(a b) ‘(c d)) list-copy takes a list and returns a copy of it • List-copy is a Lisp built-in (as copy-list) that concatenation of any number of lists (a b c d) • The new list has the same elements, but could be defined in Scheme as: > (append ‘((a)(b)) ‘(((c)))) contained in new pairs • Append copies its (define (list-copy s) arguments except ((a) (b) ((c))) > (set! x ‘(a b c)) (if (pair? s) the last > (append ‘(a b) ‘(c d) ‘(e)) (a b c d e) (a b c) (cons (list-copy (car s)) –If not, it would have > (set! y (list-copy x)) to modify the lists >(append ‘(a b) ‘()) (list-copy (cdr s))) (a b) (a b c) –Such side effects s)) are undesirable in >(append ‘(a b)) • Spend a few minutes to draw a box diagram • Given a non-atomic s-expression, it makes and functional (a b) of x and y to show where the pointers point returns a complete copy (e.g., not just the top- languages >(append) level spine) () Append Visualizing Append Visualizing Append > (load "append2.ss") > (require racket/trace) > (load "append2.ss") environment • The two argument version of append could be > (define L1 '(1 2)) > (trace append2) > (define L1 '(1 2)) VAR VALUE > (append2 L1 L2) defined like this > (define L2 '(a b)) > (define L2 '(a b)) a b >(append2 (1 2) (a b)) … (define (append2 s1 s2) > (define L3 (append2 L1 L2)) > (define L3 > L3 > (append2 (2) (a b)) (append2 L1 L2)) L2 (if (null? s1) (1 2 a b) > >(append2 () (a b)) > L3 s2 > L1 < <(a b) (1 2 a b) L1 < (2 a b) (cons (car s1) (1 2) > L1 1 2 <(1 2 a b) L3 > L2 (1 2) (append2 (cdr s1) s2)))) (1 2 a b) (a b) > L2 … • Notice how it ends up copying the top level list (a b) Append does not modify its arguments. It makes structure of its first argument > (eq? (cdr (cdr L3) L2) Append2 copies the top level of its copies of all of the lists save the last. #f first list argument, L1 4 List access functions List-ref and list-tail Defining Scheme’s list-ref & list-tail > (define L '(a b c d)) > (list-tail L 0) (define (mylist-ref l n) • To find the element at a given position in a list > (list-ref L 2) (a b c d) (cond ((< n 0) (error...)) use the function list-ref (nth in CL) c > (list-tail L 2) ((not (pair? l)) (error...)) > (list-ref ‘(a b c) 0) > (list-ref L 0) (c d) ((= n 0) (car l)) a a > (list-tail L 4) (#t (mylist-ref (cdr l) (- n 1))))) • To find the nth cdr, use list-tail (nthcdr in CL) > (list-ref L -1) () (define (mylist-tail l n) list-ref: expects type <non-negative > (list-tail L 5) > (list-tail ‘(a b c) 2) exact integer> as 2nd arg, given: -1; (cond ((< n 0) (error...)) other arguments were: (a b c d) list-tail: index 5 too large for list: (a b (c) c d) ((not (pair? l)) (error...)) > (list-ref L 4) • Both functions are zero indexed ((= n 0) l) list-ref: index 4 too large for list: (a b c d) (#t (mylist-tail (cdr l) (- n 1))))) Accessing lists Member Recall: defining member • Scheme’s last returns the last element in a list • Member returns true, but instead of simply (define (member X L) > (define (last l) returning t, its returns the part of the list (if (null? (cdr l)) beginning with the object it was looking for. (cond ((null? L) #f) (car l) > (member ‘b ‘(a b c)) ((equal? X (car L)) L) (last (cdr l)))) (b c) (#t (member X (cdr L))))) (last ‘(a b c)) • member compares objects using equal? c • 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 And that take an arbitrary function a string of up to four as or ds.

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    6 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us