TDDC74 Programming: Abstraktion och modellering VT 2014 Johannes Schmidt Institutionen för datavetenskap Linköpings universitet Lecture 5 List Structures * * * * * * * * * last years Dugga1 Iterative processing of lists LETREC eq?, eqv?, equal? Lists of lists Break: Muddy cards Lists as Trees, binary search filter, map, enumerate, accumulate Data Abstraction * SICP 2, Del 2 Program pattern: #1i Iterative processing of lists (DEFINE (FN SEQ) (DEFINE (ITER SEQ RESULT) (IF (NULL? SEQ) RESULT (ITER (CDR SEQ) (accum RESULT)))) (ITER SEQ <null-result>)) (define (mylength seq) (define (iter seq result) (if (null? seq) result (iter (cdr seq) (+ result 1)))) (iter seq 0)) New syntax: LETREC as LET but for procedures with recursive calls (define (mylength seq) (letrec ((iter (lambda (seq result) (if (null? seq) result (iter (cdr seq) (+ result 1)))))) (iter seq 0))) Compare with: (define (mylength seq) (define (iter seq result) (if (null? seq) result (iter (cdr seq) (+ result 1)))) (iter seq 0)) Program pattern: #2 Lists where certain elements shall be treated in a special way Three cases: Empty list: '() The first element is among those that shall get a special treatment: (2 a b c) The first element is not special, continue with the rest of the list: (a b c) Program pattern: #2 Lists as sequences. Example: Membership test (DEFINE (FN SEQ) (COND ((NULL? SEQ) <null-result>) (<condition> <result>) (ELSE (<operation> (FN (CDR SEQ)))))) (define (element? e seq) (cond ((null? seq) #f) ((eq? e (car seq)) #t) (else (element? e (cdr seq))))) eq? or equal? Simple difference: (define x '(1 2 3)) (define y x) (define z '(1 2 3)) (eq? x y) => #t (eq? x z) => #f (equal? x y) => #t (equal? x z) => #t And eqv? eq? compares references to objects (without evaluating the objects content) equal? compares the content of objects, goes down into the structre/content eqv? as eq?, but some differences for numbers and characters, see http://www.racket-lang.org/ Program pattern: #3 lists where elements are lists Three possible cases: Empty list: '() First element is no list: (a (b c) (d)) General case: ((a b) (b c) (d)) Program pattern: #3 lists where elements are lists (define subst (lambda (lol old new) ; substitute occurrences of old with ; new in lol (list of lists) at all levels (cond ((null? lol) '()) ((atom? (car lol)) (cond ((eq? (car lol) old) (cons new (subst (cdr lol) old new))) (else (cons (car lol) (subst (cdr lol) old new))))) (else (cons (subst (car lol) old new) (subst (cdr lol) old new)))))) Trees in programming root 3 parent children 8 2 9 6 4 leaves 7 Each node has: 1. Value 2. 0 or more children Very often: binary trees: Left child, right child Why trees? Many reasons. Example: fast search. 5 8 2 12 10 3 15 vs 8 3 12 2 5 10 15 Depth 0 1 2 Tree height = max depth + 1 i.e. here: 3 Node / tree representation A node-entity, with methods: get-value – returns the nodes value get-left-child – returns the left branch get-right-child – returns the right branch leaf? – test if the tree is a leaf (no children) empty? – test if the tree is empty Program Pattern: #4 Lists as Trees Three Cases: Empty tree: '() Atomic Tree, Leaf: a General case: no leaf, so called internal node Program pattern: #5 Lists as binary trees (define (fn tree) (cond ((empty? tree) <null-result>) ((leaf? tree) <leaf-result>) (else (<operation> (fn (get-left tree)) (fn (get-right tree)))))) Program Pattern: #5 Lists as binary trees (define (fn tree) (cond ((empty? tree) <null-result>) ((leaf? tree) <leaf-result>) (else (<operation> (fn (get-left tree)) (fn (get-right tree)))))) (define (count-leaves tree) (cond ((empty? tree) 0) ((leaf? tree) 1) (else (+ (count-leaves (get-left tree)) (count-leaves (get-right tree)))))) Program Pattern: #5 Lists as binary trees (define (fn tree) (cond ((empty? tree) <null-result>) ((leaf? tree) <leaf-result>) (else (<operation> (fn (get-left tree)) (fn (get-right tree)))))) (define (height t) (cond ((empty? t) 0) ((leaf? t) 1) (else (+ 1 (max ((height (get-left t))) (height (get-right t)))))) Node / tree implementation get-value – returns the nodes value get-left – returns the left branch get-right – returns the right branch leaf? – test if the tree is a leaf (no children) empty? – test if the tree is empty (define (make-tree value left right) (list value left right)) (define (get-value tree) (car tree)) (define (get-left tree) (car (cdr tree))) (define (get-right tree) (car (cdr (cdr tree)))) (define (leaf? tree) (and (empty? (get-left tree)) (empty? (get-right tree)))) (define (empty? tree) (null? tree)) Higher order procedures for lists We will go through some interesting eamples: Filter Map Enumerate Accumulate filter (filter) (filter proc L) apply proc to all elements in L and create a list that contains only those elements e for which (proc e) is #t. map (map proc L) map applies proc to the elements in L and returns the result as a new list. map is already built-in in Scheme and is a little more general then this description here. Enumerate (define (enumerate low high) (if (> low high) '() (cons low (enumerate (+ low 1) high)))) > (enumerate 1 5) '(1 2 3 4 5) Accumulate (accumulate proc null-value list) -> value Recursively applies proc to the list and accumulates a result that finally is returned Accumulate (define (accumulate proc null-value L) (if (null? L) null-value (proc (car L) (accumulate proc null-value (cdr L))))) > (accumulate + 0 '(1 2 3 4)) 10 ; (+ 1 (+ 2 (+ 3 (+ 4 0)))) Accumulate > (accumulate list '() '(a b c)) '(a (b (c ()))) ;(list 'a (list 'b (list > (accumulate (lambda (x y) (if (> (abs x) (abs y)) (abs x) (abs y))) 0 '(3 -6 4 -5)) 6 'c '()))) Program as a flow of sequence operations List the first 10 numbers in the Fibonacci series > (accumulate cons '() (map fib (enumerate 0 9))) '(0 1 1 2 3 5 8 13 21 34) Program as a flow of sequence operations What is the highest programmer salary? (accumulate max 0 (map salary (filter programmer? salary-db))) Program as a flow of sequence operations Which integer in the inverval 1-10000 is a perfect number? (filter perfect? (enumerate 1 10000)) SICP on Data Abstraction The basic idea of data abstraction is to structure the programs that are to use compound data objects so that they operate on “abstract data.” That is, our programs should use data in such a way as to make no assumptions about the data that are not strictly necessary for performing the task at hand. At the same time, a “concrete” data representation is defined independent of the programs that use the data. The interface between these two parts of our system will be a set of procedures, called selectors and constructors, that implement the abstract data in terms of the concrete representation. – Abelson, Sussman, & Sussman: SICP SICP on Data Abstraction The basic idea of data abstraction is to structure the programs that are to use compound data objects so that they operate on “abstract data.” That is, our programs should use data in such a way as to make no assumptions about the data that are not strictly necessary for performing the task at hand. At the same time, a “concrete” data representation is defined independent of the programs that use the data. The interface between these two parts of our system will be a set of procedures, called selectors and constructors, that implement the abstract data in terms of the concrete representation. – Abelson, Sussman, & Sussman: SICP Data Abstraction: The Philosophy Base your programs on abstract descriptions of the data, not a specific physical realisation of it Making your programs independent of the physical representation has the advantage of not needing to change your program when the physical representation of the data changes Data abstraction makes our programs easier to read Data abstraction makes top-down design of your programs possible Data Abstraction: How? Data abstraction is done by defining the procedures that create data, select from data, recognize data, change data, and also print data Data Abstraction: How? Define the procedure‘s behaviour (input, output), that you need to solve your problem Write a solution to your problem using these procedures Then implement your procedures