1 / 118

Introduction to Computer Science I Topic 5: Abstracting Design

Introduction to Computer Science I Topic 5: Abstracting Design. Prof. Dr. Max Mühlhäuser Dr. Guido Rößling. Outline. Similarities in definitions Functions are values Designing abstractions from examples Designing abstractions with functions as values Defining functions on the fly

kirima
Download Presentation

Introduction to Computer Science I Topic 5: Abstracting Design

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Introduction to Computer Science ITopic 5: Abstracting Design Prof. Dr. Max Mühlhäuser Dr. Guido Rößling

  2. Outline • Similarities in definitions • Functions are values • Designing abstractions from examples • Designing abstractions with functions as values • Defining functions on the fly • “pipes-and-filters” organization of computations

  3. Similarities in definitions • Many data and function definitions look alike: • data: a list of symbols, a list of numbers, … • functions: • searching for a specific symbol in a list of symbols • searching for a specific number in a list of numbers • … • Repetitions are the source of programming mistakes • Eliminating them is the most important step in the (program) editing process • This part of the lecture is about: • Identifying similarities in function and data definitions • Design recipes to build abstractions to avoid repetitions • The role of higher-order procedures in the abstraction process

  4. Similarities in functions • The use of our current design recipes determines a function's template (or basic organization) from the data definition for the input • The template is an alternative method of expressing what we know about the input data. • Consequence: functions that use the same kind of data look similar Get your data structures correct first, and the rest of the program will write itself. David Jones

  5. Two similar functions ;; contains-doll? : los  ->  boolean ;; to determine whether alos contains ;; the symbol 'doll (define ( contains-doll? alos) (cond [(empty? alos) false] [else (cond [(symbol=? (first alos) 'doll) true] [else ( contains-doll? (rest alos ))])]))

  6. Two similar functions ;; contains-car? : los  ->  boolean ;; to determine whether alos contains ;; the symbol 'car (define ( contains-car? alos) (cond [(empty? alos) false] [else (cond [(symbol=? (first alos) 'car ) true] [else ( contains-car? (rest alos))])]))

  7. A more abstract function • The more abstract function below requires an additional parameter: the symbol that we are looking for • It is otherwise like the two original functions ;; contains? : symbol los -> boolean;; to determine whether alos contains the symbol s (define (contains? s alos) (cond [(empty? alos) false] [else (cond [(symbol=? (first alos) s) true] [else (contains? s (rest alos))])]))

  8. Functional abstraction • Defining abstract versions of functionsis highly beneficial • A single function can perform many different tasks: • contains? can search for many different symbols instead of just one concrete symbol • Defining the single version solves many related problems at once • The process of combining two related functions into a single definition is called functional abstraction

  9. Two other similar functions less-than ;; less-than: lon number -> lon ;; constructs a list of those numbers ;; in alon that are less than t (define (less-than alon t) (cond [(empty? alon) empty] [else (cond [(< (first alon) t) (cons (first alon) (less-than(rest alon) t))] [else (less-than(rest alon) t)])]))

  10. Two other similar functions greater-than ;; greater-than: lon number  ->  lon ;; to construct a list of those numbers ;; in alon that are greater than threshold t (define (greater-than alon t) (cond [(empty? alon) empty] [else (cond [(> (first alon) t) (cons (first alon) (greater-than (rest alon) t))] [else (greater-than (rest alon) t)])]))

  11. Abstracting over the two functions • The additional parameter, rel-op, of filter1stands for both concrete relational operators in less-thanand greater-than: (define (filter1rel-opalont) (cond [(empty?alon) empty] [else (cond [(rel-op (firstalon) t) (cons (firstalon) (filter1rel-op (restalon) t))] [else (filter1rel-op (restalon) t)])])) update: rel-op -> rel-op

  12. Original functions from abstraction • To apply filter1 we must supply 3 arguments: • a relational operator R that compares two numbers, • a listL of numbers, a number N • filter1 extracts all those items i in L for which (R i N) evaluates to true • We can now define our functions less-than and greater-than as one-liners using filter1 • less-than1,resp. greater-than1, produce the same results as less-than,resp. greater-than, on the same inputs ;; less-than1:lonnumber  ->  lon (define(less-than1 alont) (filter1<alont)) ;; greater-than1:lonnumber  ->  lon (define(greater-than1alont) (filter1>alont)) ;; less-or-equal:lonnumber  ->  lon (define(less-or-equalalont) (filter1<=alont))

  13. Reusing abstract functions • We can put an abstract function to other uses: • The first argument of filter1 can be any function that uses two numbers and produces a boolean • Examples: • (filter1 = alon t): extracts all those numbers in alon that are equal to t. • (filter1 <= alon t): produces the list of numbers in alon that are smaller than or equal to t. • (filter1 >= alon t): computes the list of numbers >= t. • the following expression extracts those numbers in (list 1 2 3 4 5) with a square value larger than 10. (filter1squared>?(list12345) 10) ;; squared>?:numbernumber  ->  boolean (define (squared>?xc) (> (*xx) c))

  14. Similarities in Data Definitions • Given the similarity between the data definitions, functions that use elements of these classes of data are similar, too. (define-structir (nameprice)) An IR (Inventory Record) is a structure:  (make-ir n p)  where nis a symbol and pis a number

  15. Similarities in data definitions ;; less-than:numberlon  ->  lon ;; to construct a list of those numbers ;; on alon that are less than t (define(less-than alont) (cond [(empty?alon) empty] [else (cond [(< (firstalon) t) (cons (firstalon) (less-than(restalon) t))] [else(less-than (restalon) t)])]))

  16. Similarities in data definitions ;; less-than-ir:numberloIR  ->  loIR ;; to construct a list of those records ;; on aloir that contain a price less than t (define(less-than-iraloirt) (cond [(empty?aloir) empty] [else (cond [(<ir (firstaloir) t) (cons (firstaloir) (less-than-ir(restaloir) t))] [else(less-than-ir(restaloir) t)])])) ;; <ir:IRnumber  ->  boolean (define (<irirp) (< (ir-priceir) p))

  17. Polymorphic functions • If we abstract over less-than and less-than-ir, we obtain again filter1. • Hence, we can define less-than-irin terms of filter1: (define(less-than-ir1 aloir t)(filter1 <iraloir t)) • The abstract function filter1 can filter not only lists of numbers but also lists of arbitrarythings: • As long as we can define a function that compares these arbitrary things with numbers • More abstract: … as long as we can define a function that compares list of items with items passed to filter1as the second argument • Have a look at the following function…

  18. Polymorphic functions ;; find:loIRsymbol  ->  boolean ;; determines whether aloir contains a record for t (define (findaloirt) (cons? (filter1eq-ir?aloirt))) ;; eq-ir?:IRsymbol  ->  boolean ;; to compare ir's name and p (define (eq-ir?irp) (symbol=? (ir-nameir) p)) • filter1uniformly works on many shapes of input data: • filter1applied to a list of X returns a list ofX - no matter what kind of Scheme data Xis • Polymorphicorgeneric function

  19. Parametric data definitions • Question: How do we write precise contracts for polymorphic functions such as filter1? • Answer: Use data definitiions with parameters, so-called parametric data definitions • Do not specify everything about a class of data • Use variables to say that any form of Scheme data can be used in a certain place TYPE VARIABLE • An arbitrary collection of Scheme data: symbol, IRs, etc. • Replace ITEM with one of the following names to get a concrete instance of this abstract data definition: • lists of symbols, list of numbers, list of IRs, etc. • A list of ITEMis • either empty or • or (cons s l) • s is an ITEM • l is a list of ITEM. 

  20. Contracts for polymorphic functions • In defining contracts, the abbreviation (listof X) states that a function works on all lists: ;; length: (listofX)  ->  number ;; to compute the length of a list (define (lengthalox) (cond [(empty?alox) 0] [else (+ (length (restalox)) 1)])) • Xis just a variable  a name that stands for some class of data • If we applylengthto an element of, say, (listof symbol)or(listof IR),we get a number

  21. Outline • Similarities in definitions • Functions are values • Designing abstractions from examples • Designing abstractions with functions as values • Defining functions on the fly • “pipes-and-filters” organization of computations

  22. The value of procedures • We have already discussed the value of procedures: • Isolate the implementation of a concept: “separation of concerns” instead of code repetition • Code Reuse • Changes at one place only, etc. • Allows recursion • Unit of information hiding • The procedures that we have been using so far are called first-order procedures • In this lecture, we have used a new, more powerful kind of procedures called higher-order procedures • Higher-order procedures take other procedures as parameters or return procedures as their result

  23. Procedures as general methods • First-order procedures: make procedures independent of particular data involved (numbers, symbols etc.) • Higher-order procedures: express general methods of computation, independent of the particular functions involved • Let us take a more systematic look at higher-order procedures • We will need to first adopt Scheme’s basic definition • Higher-order functions violate the basic language definition • From now on, you should use the “Intermediate Student with Lambda” language level in DrScheme • Then we continue to discuss contracts for polymorphic functions

  24. imporant update:grammar had issues, i.e. <fct> Two violations of the basic language definition (filter1< (cons4empty) 5) Violation 1: Reason: An argument is an expression and the class of expressions does not include function names Function names as arguments in applications (define (findaloirt) (cons? (filter1eq-ir?aloirt)))

  25. Two violations of the basic language definition Violation 2: Violation 2: Parameters are used in the first position of applications (as if they were functions). (define (filter1rel-opalont) (cond [(empty?alon) empty] [else (cond [(rel-op (firstalon) t) (cons (firstalon) (filter1rel-op (restalon) t))] [else (filter1rel-op (restalon) t)])])) Reason: Our grammar allows only names of functions (<fct>) and primitive operations (<prm>) in this place, but not parameters

  26. update:<fct> added in Grammar Adjusting basic Scheme • Include the names of functions and primitive operations in the definition of <exp> • Allow the first position in an application to be things other than function names and primitive operations: • At least variables that correspond to function parameters • more generally: any expression

  27. Adjusting basic Scheme • The accommodation of higher-order functions does not lengthen the grammar; it rather makes it simpler! Caution: stillsimplified; manysubstitutionsareinvalid! 27

  28. Adjusting basic Scheme • The evaluation rules do not change at all • What changes is the set of values: it includes the names of functions and primitive operations

  29. Contracts for abstractand polymorphic functions • What is the problem? • Our new functions use a type of values that we never before used as data: • Primitive operations and other functions • To write contracts for functions of functions, we need a way to describe the new class of values: primitive operations and other functions • That is why we have so far postponed writing contracts for these functions • This is what we will consider in the next few slides

  30. Contracts for abstractand polymorphic functions • We do have contracts for first-order functions, e.g., ;; rel-op:numbernumber  ->  boolean • We say that “” describes a class of values: the class of functions • Names on the left of  ””  specify what each value in the class of functions must be applied to • The name on the right of  ”” states what each value in the class of functions is going to produce, if applied to proper values • In general:(A B  C)denotes the class of functions that take an element in Aand an element inBand produce an element in C • They are functions “from A and B to C”

  31. Example contract definitions ;; filter1: (numbernumber -> boolean) lonnumber -> lon ;; to construct the list of those numbers n on alon for which ;; (rel-opnt) evaluates to true (define (filter1rel-opalont) ...) More abstract version of filter1 filter1: (Xnumber -> boolean) (listofX) number -> (listofX) Xstands for an arbitrary collection of Scheme data. We can replace it with anything, as long as all three occurrences are replaced by the same thing.

  32. Applying functions of functions listofnumber Does this application make sense? (filter1< (list3810) 2 ) (numbernumber -> boolean) The two classes – listof numberand(number number-> boolean)are identical to the first two argument parts offilter1'scontract if Xis replaced by number filter1: (Xnumber -> boolean) (listofX) number -> (listofX) Generally: to ensure that arguments make sense, we must find replacements of the variables in contracts so that the contract and the classes of the arguments match.

  33. A new use for filter1 • Using filter1 to extract all toys with the same name from a list of inventory records: ;; find: (listofIR) symbol -> (listofIR) (define (findaloirt) (filter1eq-ir?aloirt)) ;; eq-ir?:IRsymbol -> boolean (define (eq-ir?irs) (symbol=? (ir-nameir) s)) • Problem: “Threshold” argument in this use of filter1is a symbol, not a number  conflict with the contract of filter1 • To overcome the problem, we make the contract more abstract by introducing a new variable, THfor thresholds, that stands for an arbitrary class of data: filter1: (XTH -> boolean) (listofX) TH -> (listofX)

  34. Summary: Contracts and Types • Function contracts are made up of TYPEs: • basic types, e.g., number, symbol, boolean, empty • defined types, e.g., inventory-record, list-of-numbers, family-tree • function types, e.g., (number -> number) • parametric types: either a defined types or function types with type variables • To use a function with a parametric type: • Find a replacement for all variables in the contract of the function so that the arguments belong to proper classes • If this cannot be done either revise the contract or question the decision to reuse the function

  35. Outline • Similarities in definitions • Functions are values • Designing abstractions from examples • Designing abstractions with functions as values • Defining functions on the fly • “pipes-and-filters” organization of computations

  36. Recipe for abstracting from examples • We have already abstracted designs from two concrete function definitions: • compare examples, • mark differences, • abstract • Now we formulate these steps as a recipe: • Compare the examples and mark the differences by boxes • Abstract if boxes contain values • Test the validity of the abstraction • Formulate the contract of the abstraction

  37. Comparing examples • When we find two function definitions that are almost the same except at a few places and for their names: • We compare them and mark the differences with boxes • If the boxes contain only values, we can abstract ;; names:loIR -> los (define (namesaloIR) (cond [(empty?aloIR) empty] [else (cons (IR-name (firstaloIR)) (names (restaloIR)))] )) Each box contains a functional value, so we can abstract …

  38. Two steps of the abstraction • Replace the contents of corresponding pairs of boxes with new names and add these names to the parameter list. • We need as many names as there are pairs of boxes (define (names faloIR) (cond [(empty?aloIR) empty] [else (cons (f (firstaloIR)) (names (restaloIR)))] ))

  39. Two steps of the abstraction • The two definitions must now be the same, except for the function names • To obtain the abstraction, systematically replace the function names with one new name mapcaptures a common pattern for operations over lists  it abstracts over the operation to be performed on the elements of the list

  40. Testing the abstraction • Goal: Validate that the new function is a correct abstraction of the original concrete functions. • Approach: • Define original functions in terms of the abstract one • Test the new versions with the examples formulated in the process of defining the original functions

  41. Defining the original functionsin terms of the abstraction • Assumptions: • The abstract function is calledf-abstract, • One original function is called f-original and uses one argument • If f-original differs from the other concrete function in the use of one value, say, boxed-value, then we define the following function: • For every proper value V, the following should hold: (define (f-from-abstractx) (f-abstractboxed-valuex)) (f-from-abstract V) = (f-original V)

  42. Defining the original functionsin terms of the abstraction To ensure that these two definitions are equivalent to the old ones, i.e., that map is a correct abstraction, apply these two functions to examples specified for the development of convertCF and names ;; convertCF-from-map:lon -> lon(define (convertCF-from-mapalon) (mapC->Falon)) ;; names-from-map:loIR -> los (define (names-from-mapaloIR) (mapIR-namealoIR))

  43. Formulating the contract • Goal: Formulate a contract for the abstract function • Note: In general, one cannot formulate the contract of the abstract function by looking at it as an abstraction of one or the other original functions If we view mapas an abstraction of convertCF,we get: (number -> number) (listofnumber) -> (listofnumber) If we view mapas an abstraction of names,we get: (IR -> symbol) (listofIR) -> (listofsymbol) The first contract would be useless in the second case, and vice versa

  44. Formulating general contracts • By looking at the definition, we can see: • map applies its first argument - a function f - to every item on the second argument - a list l • This implies: • f must use the data that l contains • Hence, f has the contract X -> ??? if l contains values of class X • If f produces Ys, map produces a list of Ys: map : (X -> Y) (listof X) -> (listof Y)

  45. Contracts and new uses of abstract functions • An abstract function is generally useful in a much broader context than we first anticipated: • For example, map can be used whenever we need to produce a new list by processing all items on an existing list ;; list-of-squares: (listof numbers) -> (listof numbers) ;; constructs the list of squares of the elements of alon (define (list-of-squares alon) (cond [(empty? alon) empty] [else (cons (sqr (first alon)) (list-of-squares (rest alon)))])) (list-of-squares (list 1 2 3 4 5)) --> (list 1 4 9 16 25) (define (list-of-squares list) (map sqr list))

  46. Contracts and new uses of abstract functions • Question: How do we discover new uses of abstract functions? • We have no recipe to guide the discovery process • It is a matter of practice to have an eye for matching abstract functions to situations • The formulation of the contract is important to increase the usefulness of an abstract function: • Formulate contracts that describe the applicability of abstract functions in the most general terms possible

  47. Formulating general contracts • Abstracting contracts follows the same recipe as for abstracting functions: • Compare contracts of examples from which we create abstractions • Replace specific classes in corresponding positions, one at a time, to make the contract more general • Check that the contract properly describes the specific instances of the abstracted function   (number -> number) (listofnumber) -> (listofnumber) X Y (IR -> symbol) (listofIR) -> (listofsymbol) (X -> Y) (listof X) -> (listof Y)

  48. [Recall … ] • First-order procedures: Make procedures independent of particular data (numbers, symbols, …) involved • Higher-order procedures: Express general methods of computation, independent of the particular functions involved • Let us examine what that means by the example of map…

  49. Higher-order functions as abstraction barriersby the example of map (define (list-of-squares alon) (cond [(empty? alon) empty] [else (cons (sqr (first alon)) (list-of-squares (rest alon)))])) • The above version of list-of-squaresis sub-optimal because of two reasons: • It draws attention to the element-by-element processingof lists • It reveals too much details about the implementation of lists: how list elements are extracted and combined • The operation to apply to each element is hard-coded

  50. Higher-order functions as abstraction barriersby the example of map (define (list-of-squares list) (map sqr list)) • The map version of list-of-squaressuppresses this level of detail • Itemphasizesthat squaring is a transformationof a list of elements to another list of results • Higher level of abstractionin dealing with lists • The computer is performing the same process • The differenceis that we think differently about the process!

More Related