Com S 342 meeting -*- Outline -*- * Adding Arrays (6.1) Note: Remind students to get the revised chapter 6, if they have an older copy of the book! Warning to students: we do things differently, even from the revision... ** context Q: What's missing from our defined langauge so far? make a list ------------------------------------------ AGGREGATE DATA STRUCTURES def: an *aggregate* data structure is How is aggregate data passed to procedures? ------------------------------------------ ... one that has multiple elements, such as an array or record. ... in C/C++: indirect = pass pointer to cell containing first element the pointer is passed by value, so assigning it doesn't change the aggregate What else could be done? in Pascal: direct = pass a copy of the aggregate "itself", assignment changes the aggregate directly We'll add arrays to illustrate both of these ideas. but they also apply to passing objects, as in Java or Smalltalk, vs. copying them (as can be done in C++) ** syntax ------------------------------------------ ARRAYS Concrete syntax:
::= definearray [] | ::= letarray in | [] | [] := ::= | () ::= {; }* ::= [] Examples: Abstract Syntax: (define-record definearray (var len-exp)) (define-record letarray (arraydecls body)) (define-record arrayref (array index)) (define-record arrayassign (array index exp)) (define-record decl (var exp)) ------------------------------------------ ... define p = proc(b) b[0] := 3; letarray a[2] in begin a[0] := 1; a[1] := 2; p(a); a[0] end; ** array ADT Warning to students: The model is different than in the (old) book! Q: What should the first index of an array be? book will use 0, but it's a choice designers make. ------------------------------------------ ARRAY ADT Array ADT signature: make-array: (-> (number) (Array T)) array?: (-> (datum) boolean) array-ref: (-> ((Array T) natural) ) array-set! : (-> ((Array T) number T) void) array-whole-set!: : (-> ((Array T) (Array T)) void) array-copy: (-> ((Array T)) (Array T)) array-length : (-> ((Array T)) number) Behavior: (array? (make-array n)) = (array? (array-copy a)) = (array? (vector 3 4)) = (let ((a (make-array 2)) (b (make-array 2))) (array-set! a 0 227) (array-set! a 1 228) (array-set! a 0 342) (array-whole-set! b a) (list "a[0]" (array-ref a 0) "b[1]" (array-ref b 1) "eq?" (eq? a b))) = (array-length (make-array n)) = ------------------------------------------ ... T ... #t, #t, #f, ("a[0]" 342 "b[1]" 228 #f), n Tell them to look in $PUB/lib/array.scm for the code. array-length is a local addition to this ADT, ** base interpreter with arrays This is our basis for variations. complete thing is in $PUB/lib/ch6-base.scm ------------------------------------------ CH 6 BASE INTERPRETER ;;; Figure 6.1.2 : page 182 (define eval-exp ;; TYPE: (-> (parsed-exp Environment) ;; Expressed-Value) (lambda (exp env) (variant-case exp (varref (var) (denoted->expressed (apply-env env var))) (varassign (var exp) (void->expressed (denoted-value-assign! (apply-env env var) (eval-exp exp env)))) (letarray (arraydecls body) ------------------------------------------ Point out the differences in the varassign case. (letarray (arraydecls body) ... (eval-exp body (extend-env (map decl->var arraydecls) (map (lambda (decl) (do-letarray (expressed->number (eval-exp (decl->exp decl) env)))) arraydecls) env))) ------------------------------------------ ;; Figure 6.1.2 continued (arrayref (array index) (arrayassign (array index exp) (array-element-assign! ;; new! (else ...)))) ------------------------------------------ (arrayref (array index) ... (array-ref (expressed->array (eval-array-exp array env)) (expressed->number (eval-exp index env)))) (arrayassign (array index exp) ... (void->expressed (array-element-assign! ;; new! (expressed->array (eval-array-exp array env)) (expressed->number (eval-exp index env)) (eval-exp exp env)))) ------------------------------------------ EVALUATION OF OPERANDS (define eval-rands ;; TYPE: (-> ((list parsed-exp) ;; Environment) ;; (list Denoted-Value)) (lambda (rands env) (map (lambda (rand) (eval-rand rand env)) rands))) (define eval-rand ;; TYPE: (-> (parsed-exp Environment) ;; Denoted-Value) (lambda (exp env) (expressed->denoted (eval-exp exp env)))) (define apply-proc ------------------------------------------ want eval-rand as a separate "hook" ;; TYPE: (-> (Procedure (list Denoted-Value)) ;; Expressed-Value) (lambda (proc dvs) (variant-case proc (prim-proc (prim-op) (apply-prim-op prim-op (map denoted->expressed dvs))) (closure (formals body env) (eval-exp body (extend-env formals dvs env)) (else (error "Invalid procedure:" proc))))) Q: What else do we need to write? These are the "hooks": denoted->expressed, denoted-value-assign!, do-letarray, eval-array-exp, array-element-assign! are "hooks" that we will change as needed. ------------------------------------------ ROLES OF THE HOOKS array-element-assign! denoted->expressed denoted-value-assign! do-letarray eval-array-exp expressed->denoted ------------------------------------------ ** call by value with indirect arrays *** example ------------------------------------------ INDIRECT ARRAY MODEL EXAMPLE letarray u[3]; v[2] in let p = proc (x) begin x := v; x[0] := 0 end in begin u[0] := 5; u[1] := 6; u[2] := 4; v[0] := 3; v[1] := 8; p(u); print(v[0]) end ------------------------------------------ draw pictures, like fig 6.1.6 NOTE THE DIFFERENCES FROM C, in which arrays are indirect, but don't have variables holding them. This example prints 0, because the assignment x := v is a (pointer) assignment to a local (as would happen in C with pointers), and thus x[0] := 0 makes v[0] be 0, and has no affect on u. ------------------------------------------ ANOTHER INDIRECT ARRAY MODEL EXAMPLE letarray a[3] in let suma = proc (x) begin x[1] := 10; +(x[0],+(a[1],x[0])) end in begin a[0] := 7; a[1] := 5; a[2] := 3; suma(a) end ------------------------------------------ draw a picture this returns 20 *** domains ------------------------------------------ DOMAINS FOR INDIRECT ARRAYS (CALL BY VALUE) Domains: Environment = -> Denoted-Value Denoted-Value = Expressed-Value = Number + Procedure + Procedure = prim-proc + closure Array(T) = Some of the helping procedures: array->expressed : (-> ((Array Expressed-Value)) Expressed-Value) expressed->array : (-> (Expressed-Value) (list Expressed-Value)) ------------------------------------------ ... Cell(Expressed-Value) ... Array(Expressed-Value) ... {Cell(T)}* Add arrays to expressed value domain, Indirect arrays are "pointers", so cells can contain arrays Languages with such arrays are: Scheme, C, C++, CLU, Java, ... also, Java and Smalltalk treat their objects this way About the interpreter now: Q: What were those hooks (helping procedures we still need to write)? array-element-assign! and the ones in the book's 6.1.3 Q: What are the types of these free variables? ------------------------------------------ EXPRESSED <-> DENOTED FOR THE INDIRECT MODEL ;;; Figure 6.1.3 : page 183 (define denoted->expressed ;; TYPE: (-> (Denoted-Value) ;; Expressed-Value) (define expressed->denoted ;; TYPE: (-> (Expressed-Value) ;; Denoted-Value) ------------------------------------------ ... cell-ref) ... make-cell) ------------------------------------------ AUXILIARY FUNCTIONS FOR THE INDIRECT MODEL ;;; Figure 6.1.3 : page 183 (define denoted-value-assign! (define do-letarray ------------------------------------------ Fill in first the names, then the types, then talk about the implementations, asking what they should be and why (define denoted-value-assign! ;; TYPE: (-> (Denoted-Value Expressed-Value) void) cell-set!) (define do-letarray ;; TYPE: (-> (number) Denoted-Value) (lambda (n) (if (not (<= 0 n)) ; added error check vs. text (error "do-letarray: bad index") (make-cell (array->expressed (make-array n)))))) ------------------------------------------ MORE AUXILIARY FUNCTIONS FOR THE INDIRECT MODEL (define eval-array-exp ;; addition to figure 6.1.3 (define array-element-assign! ------------------------------------------ (define eval-array-exp ;; can't eta-reduce this, as eval-exp isn't def'd yet ;; TYPE: (-> (parsed-exp Environment) Expressed-Value) (lambda (exp env) (eval-exp exp env))) ;; addition to figure 6.1.3 (define array-element-assign! ;; TYPE: (-> ((Array Expressed-Value) number Expressed-Value) void) array-set!) Recap: Q: How does that make it call by value for parameters? Best to work over some example with pictures again ** call by value with direct arrays Recall what is meant by direct arrays: no pointers to arrays, no arrays "inside" array elements i.e., no cells containing arrays Languages with direct arrays: Pascal, Ada, FORTRAN, ... *** example ------------------------------------------ DIRECT ARRAY MODEL EXAMPLE letarray u[3]; v[2] in let p = proc (x) begin x := v; x[0] := 0 end in begin u[0] := 5; u[1] := 6; u[2] := 4; v[0] := 3; v[1] := 8; p(u); print(v[0]) end ------------------------------------------ Draw pictures This example prints 3, because the assignment x := v copies elements, but leaves x as a separate array from v, and thus x[0] := 0 has no effect on v. ------------------------------------------ ANOTHER DIRECT ARRAY MODEL EXAMPLE letarray a[3] in let suma = proc (x) begin x[1] := 10; +(x[0],+(a[1],x[0])) end in begin a[0] := 7; a[1] := 5; a[2] := 3; suma(a) end ------------------------------------------ draw a picture this returns 15, not 20 like the indirect model Q: Can two array names name the same array in the direct model? no, might want to draw a picture, contrast with indirect model *** domains ------------------------------------------ DOMAINS FOR DIRECT ARRAYS (CALL BY VALUE) Domains: Environment = -> Denoted-Value Denoted-Value = Expressed-Value = Number + Procedure + Void + Array(Storable-Value) Procedure = prim-proc + closure Array(T) = {Cell(T)}* Storable-Value = ------------------------------------------ ... Cell(Storable-Value) + Array(Storable-Value) ... Number + Procedure (also lists can be storable values) Q: Can you have multi-dimensional arrays with the direct model? not unless they are built in to the language ------------------------------------------ STORABLE-VALUE DOMAIN FOR THE DIRECT MODEL number->storable : (-> (number) Storable-Value) storable->number : (-> (Storable-Value) number) procedure->storable : (-> (Procedure) Storable-Value) storable->procedure : (-> (Storable-Value) Procedure) storable->denoted : (-> (Storable-Value) Denoted-Value) expressed->storable : (-> (Expressed-Value) Storable-Value) storable->expressed : (-> (Storable-Value) Expressed-Value) ------------------------------------------ ------------------------------------------ DENOTABLE-VALUE DOMAIN FOR THE DIRECT MODEL make-cell : (-> (Storable-Value) Denoted-Value) cell-ref : (-> (Denoted-Value) Storable-Value) cell-set! : (-> (Denoted-Value Storable-Value) void) cell-swap! : (-> (Denoted-Value Denoted-Value) void) array->denoted : (-> ((Array Storable-Value)) Denoted-Value) denoted->array : (-> (Denoted-Value) (Array Storable-Value)) ------------------------------------------ ------------------------------------------ EXPRESSED <-> DENOTED FOR THE DIRECT MODEL ;;; Figure 6.1.4 : page 184 (revised) (define denoted->expressed ;; TYPE: (-> (Denoted-Value) ;; Expressed-Value) (lambda (den-val) (define expressed->denoted ;; TYPE: (-> (Expressed-Value) ;; Denoted-Value) (lambda (exp-val) ------------------------------------------ ... (if (array? den-val) (array->expressed (denoted->array den-val)) (storable->expressed (cell-ref den-val))))) ... (if (array? exp-val) (array->denoted (array-copy (expressed->array exp-val))) (make-cell (expressed->storable exp-val))))) ------------------------------------------ AUXILIARY FUNCTIONS FOR THE DIRECT MODEL ;;; Figure 6.1.4 : page 184 (revised) (define denoted-value-assign! ;; TYPE: (-> (Denoted-Value ;; Expressed-Value) ;; void) (lambda (den-val exp-val) (cond ((and (not (array? den-val)) (not (array? exp-val))) ; new (cell-set! den-val (expressed->storable exp-val))) ((and (array? den-val) (array? exp-val)) ; new (array-whole-set! (denoted->array den-val) (expressed->array exp-val))) ((and (not (array? den-val)) (array? exp-val)) ; new ... (error (else (error ------------------------------------------ ------------------------------------------ AUXILIARY FUNCTIONS FOR THE DIRECT MODEL CONTINUED (define do-letarray ;; TYPE: (-> (number) Denoted-Value) (lambda (n) (if (not (<= 0 n)) ; added check (error "do-letarray: bad index") (array->denoted (make-array n))))) (define eval-array-exp ;; TYPE: (-> (parsed-exp Environment) ;; Expressed-Value) (lambda (exp env) (eval-exp exp env))) ------------------------------------------ ... "Can't assign array to non-array: " den-val exp-val)) ... "Can't assign non-array to array: " den-val exp-val))))) ------------------------------------------ FOR YOU TO DO (define array-element-assign! ;; TYPE: (-> ((Array Storable-Value) ;; number ;; Expressed-Value) ;; void) (lambda (array index value) (if (array? value) (error ------------------------------------------ ... "Cannot assign array to array element: " value) (array-set! array index (expressed->storable value)))))