Mixing and Distinguishing Data

In the preceding section, we used <#61402#><#5957#>posn<#5957#><#61402#> structures with exactly two components to represent pixels. If many of the pixels are on the x-axis, we can simplify the representation by using plain numbers for those pixels and <#61403#><#5958#>posn<#5958#><#61403#> structures for the remaining ones.
<#72178#>#tex2html_wrap72792#<#72178#> <#5986#>Figure: A small collection of points<#5986#>
Figure~#figpoints#5988> contains a sample collection of such points. Three of the five points, namely <#5989#>C<#5989#>, <#5990#>D<#5990#>, and <#5991#>E<#5991#> are on the x-axis. Only two points require two coordinates for an accurate description: <#5992#>A<#5992#> and <#5993#>B<#5993#>. Our new idea for representing points permits us to describe this class of points succinctly: <#61423#><#5994#>(make-posn<#5994#>\ <#5995#>6<#5995#>\ <#5996#>6)<#5996#><#61423#> for <#61424#><#5997#>A<#5997#><#61424#>; <#61425#><#5998#>(make-posn<#5998#>\ <#5999#>1<#5999#>\ <#6000#>2)<#6000#><#61425#> for <#61426#><#6001#>B<#6001#><#61426#>; and 1, 2, and 3 for <#61427#><#6002#>C<#6002#><#61427#>, <#61428#><#6003#>D<#6003#><#61428#>, and <#61429#><#6004#>E<#6004#><#61429#>, respectively. If we now wish to define the function <#61430#><#6005#>distance-to-0<#6005#><#61430#>, which consumes such point representations and produces their distance to the origin, we are confronted with a problem. The function may be applied to a number <#6006#>or<#6006#> a <#61431#><#6007#>posn<#6007#><#61431#>. Depending on the class to which the input belongs, <#61432#><#6008#>distance-to-0<#6008#><#61432#> must employ a different method to calculate the distance to the origin. Thus we need to use a <#61433#><#6009#>cond<#6009#>-expression<#61433#> to distinguish the two cases. Unfortunately, we don't have any operations to formulate the appropriate conditions. To accommodate this kind of function, Scheme provides <#61434#><#6010#>PREDICATES<#6010#><#61434#>, which are operations that recognize a particular form of data. The predicates for the classes of data we know are
<#70773#><#61435#><#6012#>number?<#6012#><#61435#><#70773#>, which consumes an arbitrary value and produces <#61436#><#6013#>true<#6013#><#61436#> if the value is a number and <#61437#><#6014#>false<#6014#><#61437#> otherwise;
<#70774#><#61438#><#6015#>boolean?<#6015#><#61438#><#70774#>, which consumes an arbitrary value and produces <#61439#><#6016#>true<#6016#><#61439#> if the value is a Boolean value and <#61440#><#6017#>false<#6017#><#61440#> otherwise;
<#70775#><#61441#><#6018#>symbol?<#6018#><#61441#><#70775#>, which consumes an arbitrary value and produces <#61442#><#6019#>true<#6019#><#61442#> if the value is a symbol and <#61443#><#6020#>false<#6020#><#61443#> otherwise;
<#70776#><#61444#><#6021#>struct?<#6021#><#61444#><#70776#>, which consumes an arbitrary value and produces <#61445#><#6022#>true<#6022#><#61445#> if the value is a structure and <#61446#><#6023#>false<#6023#><#61446#> otherwise.
For each structure definition, Scheme also introduces a separate predicate so that we can distinguish among distinct classes of structures. Suppose the <#6025#>Definitions<#6025#> window contains the following structure definitions:
<#6031#>(define-struct<#6031#> <#6032#>posn<#6032#> <#6033#>(x<#6033#> <#6034#>y))<#6034#>
<#6035#>(define-struct<#6035#> <#6036#>star<#6036#> <#6037#>(last<#6037#> <#6038#>first<#6038#> <#6039#>dob<#6039#> <#6040#>ssn))<#6040#> 
<#6041#>(define-struct<#6041#> <#6042#>airplane<#6042#> <#6043#>(kind<#6043#> <#6044#>max-speed<#6044#> <#6045#>max-load<#6045#> <#6046#>price))<#6046#> 
Then, Scheme also knows the following three predicates:
<#70778#><#61448#><#6051#>posn?<#6051#><#61448#><#70778#>, which consumes an arbitrary value and produces <#61449#><#6052#>true<#6052#><#61449#> if the value is a <#61450#><#6053#>posn<#6053#><#61450#> structure and <#61451#><#6054#>false<#6054#><#61451#> otherwise;
<#70779#><#61452#><#6055#>star?<#6055#><#61452#><#70779#>, which consumes an arbitrary value and produces <#61453#><#6056#>true<#6056#><#61453#> if the value is a <#61454#><#6057#>star<#6057#><#61454#> structure and <#61455#><#6058#>false<#6058#><#61455#> otherwise;
<#70780#><#61456#><#6059#>airplane?<#6059#><#61456#><#70780#>, which consumes an arbitrary value and produces <#61457#><#6060#>true<#6060#><#61457#> if the value is a <#61458#><#6061#>airplane<#6061#><#61458#> structure and <#61459#><#6062#>false<#6062#><#61459#> otherwise.
Hence, a function can distinguish a structure from a number as well as a <#61460#><#6064#>posn<#6064#><#61460#> structure from an <#61461#><#6065#>airplane<#6065#><#61461#> structure.
<#6068#>Exercise 7.1.1<#6068#> Evaluate the following expressions by hand:
  1. <#61462#><#6071#>(number?<#6071#>\ <#6072#>(make-posn<#6072#>\ <#6073#>2<#6073#>\ <#6074#>3))<#6074#><#61462#>
  2. <#61463#><#6075#>(number?<#6075#>\ <#6076#>(+<#6076#>\ <#6077#>12<#6077#>\ <#6078#>10))<#6078#><#61463#>
  3. <#61464#><#6079#>(posn?<#6079#>\ <#6080#>23)<#6080#><#61464#>
  4. <#61465#><#6081#>(posn?<#6081#>\ <#6082#>(make-posn<#6082#>\ <#6083#>23<#6083#>\ <#6084#>3))<#6084#><#61465#>
  5. <#61466#><#6085#>(star?<#6085#>\ <#6086#>(make-posn<#6086#>\ <#6087#>23<#6087#>\ <#6088#>3))<#6088#><#61466#>
Check the answers in DrScheme.~ external Solution<#61467#><#61467#>
Now we can define <#61468#><#6097#>distance-to-0<#6097#><#61468#>. Let's start with a data definition:
A <#61469#><#6099#>pixel-2<#6099#><#61469#> is either
  1. a <#61470#><#6101#>number<#6101#><#61470#>, or
  2. a <#61471#><#6102#>posn<#6102#><#61471#> structure.
Stating the contract, purpose, and header is straightforward:
<#70781#>;; <#61472#><#6109#>distance-to-0<#6109#> <#6110#>:<#6110#> <#6111#>pixel-2<#6111#> <#6112#><#6112#><#6113#>-;SPMgt;<#6113#><#6114#><#6114#> <#6115#>number<#6115#><#61472#><#70781#>
<#70782#>;; to compute the distance of <#61473#><#6116#>a-pixel<#6116#><#61473#> to the origin<#70782#> 
<#6117#>(define<#6117#> <#6118#>(distance-to-0<#6118#> <#6119#>a-pixel)<#6119#> <#6120#>...)<#6120#> 
As mentioned before, the function must distinguish among its two kinds of inputs, which can be accomplished with a <#61474#><#6124#>cond<#6124#>-expression<#61474#>:
<#6129#>(d<#6129#><#6130#>efine<#6130#> <#6131#>(distance-to-0<#6131#> <#6132#>a-pixel)<#6132#>
  <#6133#>(c<#6133#><#6134#>ond<#6134#> 
    <#6135#>[<#6135#><#6136#>(number?<#6136#> <#6137#>a-pixel)<#6137#> <#6138#>...]<#6138#> 
    <#6139#>[<#6139#><#6140#>(posn?<#6140#> <#6141#>a-pixel)<#6141#> <#6142#>...]<#6142#><#6143#>))<#6143#> 
The two conditions correspond to the two possible inputs of the new <#61475#><#6147#>distance-to-0<#6147#><#61475#> function. If the first one holds, the input is a pixel on the x-axis. Otherwise the pixel is a <#61476#><#6148#>posn<#6148#><#61476#> structure. For the second <#61477#><#6149#>cond<#6149#><#61477#>-line, we also know that the input contains two items: the <#6150#>x<#6150#> and <#6151#>y<#6151#> coordinates. To remind ourselves, we annotate the template with two selector expressions:
<#6156#>(d<#6156#><#6157#>efine<#6157#> <#6158#>(distance-to-0<#6158#> <#6159#>a-pixel)<#6159#>
  <#6160#>(c<#6160#><#6161#>ond<#6161#> 
    <#6162#>[<#6162#><#6163#>(number?<#6163#> <#6164#>a-pixel)<#6164#> <#6165#>...]<#6165#> 
    <#6166#>[<#6166#><#6167#>(posn?<#6167#> <#6168#>a-pixel)<#6168#> <#6169#>...<#6169#> <#6170#>(posn-x<#6170#> <#6171#>a-pixel)<#6171#> <#6172#>...<#6172#> <#6173#>(posn-y<#6173#> <#6174#>a-pixel)<#6174#> <#6175#>...<#6175#> <#6176#>]<#6176#><#6177#>))<#6177#> 
Completing the function is easy. If the input is a number, it <#6181#>is<#6181#> the distance to the origin. If it is a structure, we use the old formula for determining the distance to the origin:
<#6186#>(d<#6186#><#6187#>efine<#6187#> <#6188#>(distance-to-0<#6188#> <#6189#>a-pixel)<#6189#>
  <#6190#>(c<#6190#><#6191#>ond<#6191#> 
    <#6192#>[<#6192#><#6193#>(number?<#6193#> <#6194#>a-pixel)<#6194#> <#6195#>a-pixel]<#6195#> 
    <#6196#>[<#6196#><#6197#>(posn?<#6197#> <#6198#>a-pixel)<#6198#> <#6199#>(s<#6199#><#6200#>qrt<#6200#> 
                       <#6201#>(+<#6201#> <#6202#>(square<#6202#> <#6203#>(posn-x<#6203#> <#6204#>a-pixel))<#6204#> 
                          <#6205#>(square<#6205#> <#6206#>(posn-y<#6206#> <#6207#>a-pixel))))]<#6207#><#6208#>))<#6208#> 
Let us consider a second example. Suppose we are to write functions that deal with geometric shapes. One function might have to compute the area covered by a shape, another one the perimeter, and a third could draw the shape. For the sake of simplicity, let's assume that the class of shapes only includes squares and circles and that their description includes their location (a <#61478#><#6212#>posn<#6212#><#61478#>) and their size (a <#61479#><#6213#>number<#6213#><#61479#>). Information about both shapes must be represented with structures, because both have several attributes. Here are the natural structure definitions:
<#6219#>(define-struct<#6219#> <#6220#>square<#6220#> <#6221#>(nw<#6221#> <#6222#>length<#6222#><#6223#>))<#6223#>
<#6224#>(define-struct<#6224#> <#6225#>circle<#6225#> <#6226#>(center<#6226#> <#6227#>radius))<#6227#> 
and the matching data definition:
A <#61480#><#6232#>shape<#6232#><#61480#> is either
  1. a circle structure:

    <#70783#><#61481#><#6234#>(make-circle<#6234#>\ <#6235#>p<#6235#>\ <#6236#>s)<#6236#><#61481#><#70783#> where <#61482#><#6237#>p<#6237#><#61482#> is a <#61483#><#6238#>posn<#6238#><#61483#> and <#61484#><#6239#>s<#6239#><#61484#> is a number; or

  2. a square structure:

    <#70784#><#61485#><#6240#>(make-square<#6240#>\ <#6241#>p<#6241#>\ <#6242#>s)<#6242#><#61485#><#70784#> where <#61486#><#6243#>p<#6243#><#61486#> is a <#61487#><#6244#>posn<#6244#><#61487#> and <#61488#><#6245#>s<#6245#><#61488#> is a number.

Together, the two classes make up the class of shapes: The next step of our design recipe requires that we make up examples. Let's start with input examples:
  1. <#61489#><#6249#>(make-square<#6249#>\ <#6250#>(make-posn<#6250#>\ <#6251#>20<#6251#>\ <#6252#>20)<#6252#>\ <#6253#>3)<#6253#><#61489#>,
  2. <#61490#><#6254#>(make-square<#6254#>\ <#6255#>(make-posn<#6255#>\ <#6256#>2<#6256#>\ <#6257#>20)<#6257#>\ <#6258#>3)<#6258#><#61490#>, and
  3. <#61491#><#6259#>(make-circle<#6259#>\ <#6260#>(make-posn<#6260#>\ <#6261#>10<#6261#>\ <#6262#>99)<#6262#>\ <#6263#>1)<#6263#><#61491#>.
To make up examples of input-output relationships, we need to know the purpose of the function. So suppose we need the function <#61492#><#6265#>perimeter<#6265#><#61492#>, which computes the <#6266#>perimeter<#6266#> of a shape. From geometry, we know that the perimeter of a square is four times its side, the perimeter of a circle is #tex2html_wrap_inline72790# times the diameter, which is twice the radius. Thus, the perimeter of the above three examples are: <#61494#><#6268#>12<#6268#><#61494#>, <#61495#><#6269#>12<#6269#><#61495#>, and (roughly) <#61496#><#6270#>6.28<#6270#><#61496#>, respectively. Following the design recipe and the precedent of <#61497#><#6271#>distance-to-0<#6271#><#61497#>, we start with the following skeleton of the function:
<#70785#>;; <#61498#><#6276#>perimeter<#6276#> <#6277#>:<#6277#> <#6278#>shape<#6278#> <#6279#><#6279#><#6280#>-;SPMgt;<#6280#><#6281#><#6281#> <#6282#>number<#6282#><#61498#><#70785#>
<#70786#>;; to compute the perimeter of <#61499#><#6283#>a-shape<#6283#><#61499#><#70786#> 
<#6284#>(d<#6284#><#6285#>efine<#6285#> <#6286#>(perimeter<#6286#> <#6287#>a-shape)<#6287#> 
  <#6288#>(c<#6288#><#6289#>ond<#6289#> 
    <#6290#>[<#6290#><#6291#>(square?<#6291#> <#6292#>a-shape)<#6292#> <#6293#>...<#6293#> <#6294#>]<#6294#> 
    <#6295#>[<#6295#><#6296#>(circle?<#6296#> <#6297#>a-shape)<#6297#> <#6298#>...<#6298#> <#6299#>]<#6299#><#6300#>))<#6300#> 
because the function must first determine to which class <#61500#><#6304#>a-shape<#6304#><#61500#> belongs. Furthermore, each possible input is a structure, so we can also add two selector expressions to each <#61501#><#6305#>cond<#6305#><#61501#>-clause:
<#70787#>;; <#61502#><#6310#>perimeter<#6310#> <#6311#>:<#6311#> <#6312#>shape<#6312#> <#6313#><#6313#><#6314#>-;SPMgt;<#6314#><#6315#><#6315#> <#6316#>number<#6316#><#61502#><#70787#>
<#70788#>;; to compute the perimeter of <#61503#><#6317#>a-shape<#6317#><#61503#><#70788#> 
<#6318#>(d<#6318#><#6319#>efine<#6319#> <#6320#>(perimeter<#6320#> <#6321#>a-shape)<#6321#> 
  <#6322#>(c<#6322#><#6323#>ond<#6323#> 
    <#6324#>[<#6324#><#6325#>(square?<#6325#> <#6326#>a-shape)<#6326#> 
     <#6327#>...<#6327#> <#6328#>(square-nw<#6328#> <#6329#>a-shape)<#6329#> <#6330#>...<#6330#> <#6331#>(square-length<#6331#> <#6332#>a-shape)<#6332#> <#6333#>...]<#6333#> 
    <#6334#>[<#6334#><#6335#>(circle?<#6335#> <#6336#>a-shape)<#6336#> 
     <#6337#>...<#6337#> <#6338#>(circle-center<#6338#> <#6339#>a-shape)<#6339#> <#6340#>...<#6340#> <#6341#>(circle-radius<#6341#> <#6342#>a-shape)<#6342#> <#6343#>...]<#6343#><#6344#>))<#6344#> 
The selector expressions remind us of the available data. Now we are ready to finish the definition. We fill the gaps in the two answers by translating the mathematical formulae into Scheme notation:
<#6352#>(d<#6352#><#6353#>efine<#6353#> <#6354#>(perimeter<#6354#> <#6355#>a-shape)<#6355#>
  <#6356#>(c<#6356#><#6357#>ond<#6357#> 
    <#6358#>[<#6358#><#6359#>(square?<#6359#> <#6360#>a-shape)<#6360#> <#6361#>(*<#6361#> <#6362#>(square-length<#6362#> <#6363#>a-shape)<#6363#> <#6364#>4)]<#6364#> 
    <#6365#>[<#6365#><#6366#>(circle?<#6366#> <#6367#>a-shape)<#6367#> <#6368#>(*<#6368#> <#6369#>(*<#6369#> <#6370#>2<#6370#> <#6371#>(circle-radius<#6371#> <#6372#>a-shape))<#6372#> <#6373#>pi)]<#6373#><#6374#>))<#6374#> 
Since the position of a shape does not affect its perimeter, the template's selector expressions for <#61504#><#6378#>nw<#6378#><#61504#> and <#61505#><#6379#>center<#6379#><#61505#> disappear.
<#6382#>Exercise 7.1.2<#6382#> Test <#61506#><#6384#>perimeter<#6384#><#61506#> with the examples. external Solution<#61507#><#61507#> <#6390#>Exercise 7.1.3<#6390#> Develop the function <#61508#><#6392#>area<#6392#><#61508#>, which consume either a circle or a square and computes the area. Is it possible to reuse the template for <#61509#><#6393#>perimeter<#6393#><#61509#> by changing the name to <#61510#><#6394#>area<#6394#><#61510#>? external Solution<#61511#><#61511#>