[previous] [up] [next]     [index]
Next: Composing FunctionsRevisited Up: The Varieties of Data Previous: Mixing and Distinguishing Data

Designing Functions for Mixed Data

The function development in the preceding section suggests some amendments to our design recipe. Specifically, the data analysis step, the template construction step, and the definition of the function's body require adjustments.

Data Analysis and Design:
When we analyze a problem statement, our first task is to determine whether it mentions distinct classes of data--which we call MIXED DATA and which is also known as the UNION of data classes. In other words, the data analysis must take into account several aspects now. First, we must determine how many distinct classes of objects are mentioned in the problem and what their important attributes are. If there are several different classes of objects, we are mixing data. Second, we must understand whether the various objects have several properties. If an object has several attributes, we use compound data for its representation. As a result, the resulting data definition may have several clauses that enumerate several possibilities. Indeed, we will see that the data analysis may yield a hierarchy of data definitions.

The example of the preceding section deals with two distinct kinds of shapes, each of which has several properties. We captured this idea with the following data definition:

A shape is either
  1. a circle structure:
               (make-circle p s)
    

    where p is a posn and s is a number; or
  2. a square structure:
               (make-square p s)
    

    where p is a posn and s is a number.

It specifies that every shape belongs to one of two subclasses of data.

For a data definition to make sense, it must be possible to formulate conditions that distinguish the various subclasses in a definition. That is, if x stands for a piece of data in the defined class, we must be able to use built-in and user-defined predicates to distinguish the enumerated subclasses from each other. In our running example, the two conditions would be (square? x) and (circle? x).

Template:
Recall that the template is a translation of the input data definition into Scheme. Thus, imagine that we have a data definition that enumerates several distinct possibilities. The first step is to write down a cond-expression with as many clauses as there are enumerated possibilities in the data definition. The second step is to add a condition to each line. Each condition should hold if the input belongs to the corresponding subclass of data mentioned in the data definition.

Here is the template for our running example:

;; f : shape -> ???
(define (f a-shape) 
  (cond 
    [(square? a-shape) ...] 
    [(circle? a-shape) ...])) 

The output specification and the purpose statement are missing to emphasize that a template has no connection to the output or the purpose of a function.

Once we have formulated the template for the conditional, we refine the template further, cond-line by cond-line. If the purpose of a line is to process atomic information, we are done. If a line processes compound data, we enrich the template with appropriate selector expressions.

Let's illustrate the idea with our running example again:

(define (f a-shape)
  (cond 
    [(square? a-shape) 
     ... (square-nw a-shape) ... (square-length a-shape) ...] 
    [(circle? a-shape) 
     ... (circle-center a-shape) ... (circle-radius a-shape) ...])) 

Body:
Using the conditional template, we split the task into simpler tasks. Specifically, we can focus on each cond-line separately, simply considering the question what is the output if we are given this kind of input. All other cases are ignored as we work out one particular clause.

Suppose we want to define a function that computes the perimeter of a shape. Then we start from the template and fill in the gaps:

;; perimeter : shape -> number
;; to compute the perimeter of a-shape 
(define (perimeter a-shape) 
  (cond 
    [(square? a-shape) (* (square-length a-shape) 4)] 
    [(circle? a-shape) (* (* 2 (circle-radius a-shape)) pi)])) 

Figure [cross-reference] summarizes the development of our running example.

The remaining steps of the recipes in figures [cross-reference], [cross-reference], and [cross-reference] should be followed on an as-is basis. Figure [cross-reference] summarizes the design recipe, with all steps included.


;; Data Definition:
(define-struct circle (center radius)) 
(define-struct square (nw length)) 
;; A shape is either 
;; 1. a structure: (make-circle p s) 
;;    where p is a posn, s a number; 
;; 2. a structure: (make-square p s) 
;;    where p is a posn, s a number.

;; Contract, Purpose, Header: ;; perimeter : shape -> number ;; to compute the perimeter of a-shape

;; Examples: see tests

;; Template: ;; (define (f a-shape) ;;    (cond ;; [(square? a-shape) ;; ... (square-nw a-shape) ... (square-length a-shape) ...] ;; [(circle? a-shape) ;; ... (circle-center a-shape) ... (circle-radius a-shape) ...]))

;; Definition: (define (perimeter a-shape) (cond [(circle? a-shape) (* (* 2 (circle-radius a-shape)) pi)] [(square? a-shape) (* (square-length a-shape) 4)]))

;; Tests: (same as examples) (= (perimeter (make-square ... 3)) 12) (= (perimeter (make-circle ... 1)) (* 2 pi))

Figure: The design recipe for mixed data: A complete example



The figure is not yet translated into HTML.
Figure: Designing a function for mixed data

(Refines the recipes in figures [cross-reference] (pg. [cross-reference]) and [cross-reference] (pg. [cross-reference]))


Even a cursory comparative reading of the design recipes in sections [cross-reference],  [cross-reference],  [cross-reference], and the current one suggests that the data analysis and the template design steps are becoming more and more important. If we do not understand what kind of data a function consumes, we cannot design it and organize it properly. If, however, we do understand the structure of the data definition and organize our template properly, it is easy to modify or to extend a function. For example, if we add new information to the representation of a circle, then only those cond-clauses related to circles may require changes. Similarly, if we add a new kind of shape to our data definition, say, rectangles, we must add new cond-clauses to our functions.


Exercises

Exercise 7.2.1

Develop structure and data definitions for a collection of zoo animals. The collection includes

spiders,
whose relevant attributes are the number of remaining legs (we assume that spiders can lose legs in accidents) and the space they need in case of transport;

elephants,
whose only attributes are the space they need in case of transport;

monkeys,
whose attributes are intelligence and space needed for transportation.

Then develop a template for functions that consume zoo animals.

Develop the function fits?. The function consumes a zoo animal and the volume of a cage. It determines whether the cage is large enough for the animal. Solution

Exercise 7.2.2

The administrators of metropolitan transportation agencies manage fleets of vehicles. Develop structure and data definitions for a collection of such vehicles. The collection should include at least buses, limos, cars, and subways. Add at least two attributes per class of vehicle.

Then develop a template for functions that consume vehicles.  Solution



[previous] [up] [next]     [index]
Next: Composing FunctionsRevisited Up: The Varieties of Data Previous: Mixing and Distinguishing Data

PLT