Data Structures in Scheme Vectors in Scheme in Scheme, Lists and S-Expressions Scheme Provides a Vector Type Are Basic
Total Page:16
File Type:pdf, Size:1020Kb
Data Structures in Scheme Vectors in Scheme In Scheme, lists and S-expressions Scheme provides a vector type are basic. Arrays can be simulated that directly implements one using lists, but access to elements dimensional arrays. “deep” in the list can be slow Literals are of the form #( ... ) (since a list is a linked structure). For example, #(1 2 3) or To access an element deep within #(1 2.0 "three") a list we can use: The function (vector? val) • (list-tail L k) tests whether val is a vector or This returns list L after removing not. k the first elements. For example, ⇒ (list-tail '(1 2 3 4 5) 2) ⇒ (vector? 'abc) #f (3 4 5) (vector? '(a b c)) ⇒ #f • (list-ref L k) (vector? #(a b c)) ⇒ #t This returns the k-th element in L (counting from 0). For example, (list-ref '(1 2 3 4 5) 2) ⇒ 3 The function (vector v1 v2 ...) evaluates v1, v2, ... and puts them into a vector. (vector 1 2 3) ⇒ #(1 2 3) © © CS 538 Spring 2008 130 CS 538 Spring 2008 131 The function (make-vector k val) For example, creates a vector composed of k (define v #(1 2 3 4 5)) copies of val. Thus (vector-set! v 2 0) ⇒ (make-vector 4 (/ 1 2)) ⇒ v #(1 2 0 4 5) #(1/2 1/2 1/2 1/2) Vectors aren’t lists (and lists The function (vector-ref vect k) aren’t vectors). returns the k-th element of vect, Thus (car #(1 2 3)) doesn’t starting at position 0. It is work. essentially the same as vect[k] There are conversion routines: in C or Java. For example, • (vector->list V) converts ⇒ (vector-ref #(2 4 6 8 10) 3) 8 vector V to a list containing the The function same values as V. For example, (vector-set! vect k val) sets (vector->list #(1 2 3)) ⇒ the k-th element of vect, starting (1 2 3) val at position 0, to be . It is • (list->vector L) converts list L essentially the same as to a vector containing the same vect[k]=val in C or Java. The values as L. For example, value returned by the function is (list->vector '(1 2 3)) ⇒ unspecified. The suffix “!” in set! #(1 2 3) indicates that the function has a side-effect. © © CS 538 Spring 2008 132 CS 538 Spring 2008 133 • In general Scheme names a Records and Structs conversion function from type T to type Q as T->Q. For example, In Scheme we can represent a string->list converts a string record, struct, or class object as into a list containing the an association list of the form characters in the string. ((obj1 val1) (obj2 val2) ...) In the association list, which is a list of (object value) sublists, object serves as a “key” to locate the desired sublist. For example, the association list ( (A 10) (B 20) (C 30) ) serves the same role as struct { int a = 10; int b = 20; int c = 30;} © © CS 538 Spring 2008 134 CS 538 Spring 2008 135 The predefined Scheme function We can use non-atomic objects as (assoc obj alist) keys too! checks alist (an association list) (define price-list to see if it contains a sublist with '( ((bmw m5) 71095) obj as its head. If it does, the list ((bmw z4) 40495) starting with obj is returned; ((jag xj8) 56975) #f otherwise (indicating failure) is ((mb sl500) 86655) returned. ) For example, ) (define L '( (a 10) (b 20) (c 30) ) ) (assoc '(bmw z4) price-list) ⇒ (assoc 'a L) ⇒ (a 10) ((bmw z4) 40495) (assoc 'b L) ⇒ (b 20) (assoc 'x L) ⇒ #f © © CS 538 Spring 2008 136 CS 538 Spring 2008 137 Using assoc, we can easily define Scheme has a number of a structure function: predefined functions that combine (structure key alist) will several calls to car and cdr into one function. For example, return the value associated with ≡ key alist (caar x) (car (car x)) in ; in C or Java ≡ notation, it returns alist.key. (cadr x) (car (cdr x)) ≡ (define (cdar x) (cdr (car x)) (structure key alist) (cddr x) ≡ (cdr (cdr x)) (if (assoc key alist) (car (cdr (assoc key alist))) Using these two insights we can #f now define a better version of ) structure ) (define We can improve this function in (structure key alist) two ways: (let ((p (assoc key alist))) • The same call to assoc is made (if p twice; we can save the value (cadr p) computed by using a let #f expression. ) ) • Often combinations of car and cdr are needed to extract a value. ) © © CS 538 Spring 2008 138 CS 538 Spring 2008 139 What does assoc do if more than If we want to be more space- one sublist with the same key efficient, we can create a version exists? that updates the internal structure It returns the first sublist with a of an association list, using matching key. In fact, this set-cdr! which changes the cdr property can be used to make a value of a list: simple and fast function that (define updates association lists: (set-structure! key alist val) (let ( (p (assoc key alist))) (define (set-structure key alist val) (if p (cons (list key val) alist) (begin ) (set-cdr! p (list val)) alist ) (cons (list key val) alist) ) ) ) © © CS 538 Spring 2008 140 CS 538 Spring 2008 141 Functions are First-class Scoping Objects In Scheme scoping is static Functions may be passed as (lexical). This means that non- parameters, returned as the value local identifiers are bound to of a function call, stored in data containing lambda parameters, or objects, etc. let values, or globally defined values. For example, This is a consequence of the fact (define (f x) that (lambda (y) (+ x y))) (lambda (args) (body)) Function f takes one parameter, evaluates to a function just as x. It returns a function (of y), with (+ 1 1) x in the returned function bound to the value of x used when f was evaluates to an integer. called. Thus (f 10) ≡ (lambda (y) (+ 10 y)) ((f 10) 12) ⇒ 22 © © CS 538 Spring 2008 142 CS 538 Spring 2008 143 Unbound symbols are assumed to We can encapsulate internal state be globals; there is a run-time with a function by using private, error if an unbound global is let-bound variables: referenced. For example, (define cnt (define (p y) (+ x y)) (let ( (I 0) ) (p 20) ; error -- x is unbound (lambda () (define x 10) (set! I (+ I 1)) I) ) (p 20) ⇒ 30 ) We can use let bindings to create private local variables for Now, functions: (cnt) ⇒ 1 (define F (cnt) ⇒ 2 (let ( (X 1) ) ⇒ (lambda () X) (cnt) 3 ) etc. ) F is a function (of no arguments). (F) calls F. (define X 22) (F) ⇒ 1;X used in F is private © © CS 538 Spring 2008 144 CS 538 Spring 2008 145 Let Bindings can be Subtle Simulating Class Objects You must check to see if the let- Using association lists and private bound value is created when the bound values, we can encapsulate function is created or when it is data and functions. This gives us called. the effect of class objects. Compare (define (point x y) (list (define cnt (list 'rect (let ( (I 0) ) (lambda () (list x y))) (lambda () (list 'polar (lambda () (set! I (+ I 1)) I) (list ) (sqrt (+ (* x x) (* y y))) ) (atan (/ x y)) vs. ) (define reset ) (lambda () ) (let ( (I 0) ) ) ) (set! I (+ I 1)) I) ) A call (point 1 1) creates an ) association list of the form (reset) ⇒ 1, (reset) ⇒ 1, etc. ( (rect funct) (polar funct) ) © © CS 538 Spring 2008 146 CS 538 Spring 2008 147 We can use structure to access We can add new functionality by components: just adding new (id function) (define p (point 1 1) ) pairs to the association list. ( (structure 'rect p) ) ⇒ (1 1) (define (point x y) (list ( (structure 'polar p) ) ⇒ (list 'rect π (lambda () (list x y))) (2 --- ) (list 'polar 4 (lambda () (list (sqrt (+ (* x x) (* y y))) (atan (/ x y)) ))) (list 'set-rect! (lambda (newx newy) (set! x newx) (set! y newy) (list x y) )) (list 'set-polar! (lambda (r theta) (set! x (* r (sin theta))) (set! y (* r (cos theta))) (list r theta) )) )) © © CS 538 Spring 2008 148 CS 538 Spring 2008 149 Now we have Limiting Access to Internal (define p (point 1 1) ) Structure ( (structure 'rect p) ) ⇒ (1 1) ( (structure 'polar p) ) ⇒ We can improve upon our π association list approach by 2 (--4- ) returning a single function (similar to a C++ or Java object) rather than an explicit list of (id ((structure 'set-polar! p) 1 π/4) function) pairs. ⇒ (1 π/4) The function will take the name of ( (structure 'rect p) ) ⇒ the desired operation as one of its 1 1 arguments. (------- ------- ) 2 2 © © CS 538 Spring 2008 150 CS 538 Spring 2008 151 First, let’s differentiate between Stack Implemented as a (define def1 (let ( (I 0) ) Function (lambda () (set! I (+ I 1)) I) (define ( stack ) ) (let ( (s () ) ) ) (lambda (op . args) ; var # args and (cond (define (def2) ((equal? op 'push!) (let ( (I 0) ) (set! s (cons (car args) s)) (lambda () (set! I (+ I 1)) I) (car s)) ) ((equal? op 'pop!) ) (if (null? s) def1 #f is a zero argument function (let ( (top (car s)) ) that increments a local variable (set! s (cdr s)) and returns its updated value. top ))) def2 is a a zero argument ((equal? op 'empty?) function that generates a function (null? s)) of zero arguments (that (else #f) increments a local variable and ) returns its updated value).