Similarities in Data Definitions

Inspect the following two data definitions: #tex2html_wrap73216##tex2html_wrap73218# Both define a class of lists. The one on the left is the data definition for lists of numbers; the one on the right describes lists of inventory records, which we represent with structures:
<#27052#>(define-struct<#27052#> <#27053#>ir<#27053#> <#27054#>(name<#27054#> <#27055#>price))<#27055#>
An <#65043#><#27060#>IR<#27060#><#65043#> is a structure:

<#71246#><#65044#><#27061#>(make-ir<#27061#>\ <#27062#>n<#27062#>\ <#27063#>p)<#27063#><#65044#><#71246#> where <#65045#><#27064#>n<#27064#><#65045#> is a symbol and <#65046#><#27065#>p<#27065#><#65046#> is a number.

Given the similarity between the data definitions, functions that consume elements of these classes are similar, too. Take a look at the illustrative example in figure~#figcmpabovebelow2#27067>. The function on the left is the function <#65047#><#27068#>below<#27068#><#65047#>, which filters numbers from a list of numbers. The one on the right is <#65048#><#27069#>below-ir<#27069#><#65048#>, which extracts those inventory records from a list whose prices are below a certain threshold. Except for the name of the function, which is arbitrary, the two definitions differ in only one point: the relational operator.
<#71247#>;; <#65049#><#27074#>below<#27074#> <#27075#>:<#27075#> <#27076#>number<#27076#> <#27077#>lon<#27077#> <#27078#><#27078#><#27079#>-;SPMgt;<#27079#><#27080#><#27080#> <#27081#>lon<#27081#><#65049#><#71247#>
<#27082#>;; to construct a list of those numbers<#27082#> 
<#71248#>;; on <#65050#><#27083#>alon<#27083#><#65050#> that are below <#65051#><#27084#>t<#27084#><#65051#><#71248#> 
<#27085#>(d<#27085#><#27086#>efine<#27086#> <#27087#>(below<#27087#> <#27088#>alon<#27088#> <#27089#>t)<#27089#> 
  <#27090#>(c<#27090#><#27091#>ond<#27091#> 
    <#27092#>[<#27092#><#27093#>(empty?<#27093#> <#27094#>alon)<#27094#> <#27095#>empty]<#27095#> 
    <#27096#>[<#27096#><#27097#>else<#27097#> <#27098#>(c<#27098#><#27099#>ond<#27099#> 
            <#27100#>[<#27100#><#27101#>(<#27101#>#tex2html_wrap73220# <#27103#>(first<#27103#> <#27104#>alon)<#27104#> <#27105#>t)<#27105#> 
             <#27106#>(c<#27106#><#27107#>ons<#27107#> <#27108#>(first<#27108#> <#27109#>alon)<#27109#> 
               <#27110#>(below<#27110#> <#27111#>(rest<#27111#> <#27112#>alon)<#27112#> <#27113#>t))]<#27113#> 
            <#27114#>[<#27114#><#27115#>e<#27115#><#27116#>lse<#27116#> 
              <#27117#>(below<#27117#> <#27118#>(rest<#27118#> <#27119#>alon)<#27119#> <#27120#>t)]<#27120#><#27121#>)]<#27121#><#27122#>))<#27122#> 




<#71249#>;; <#65052#><#27128#>below-ir<#27128#> <#27129#>:<#27129#> <#27130#>number<#27130#> <#27131#>loIR<#27131#> <#27132#><#27132#><#27133#>-;SPMgt;<#27133#><#27134#><#27134#> <#27135#>loIR<#27135#><#65052#><#71249#>
<#27136#>;; to construct a list of those records <#27136#> 
<#71250#>;; on <#65053#><#27137#>aloir<#27137#><#65053#> that contain a price below <#65054#><#27138#>t<#27138#><#65054#><#71250#> 
<#27139#>(d<#27139#><#27140#>efine<#27140#> <#27141#>(below<#27141#> <#27142#>aloir<#27142#> <#27143#>t)<#27143#> 
  <#27144#>(c<#27144#><#27145#>ond<#27145#> 
    <#27146#>[<#27146#><#27147#>(empty?<#27147#> <#27148#>aloir)<#27148#> <#27149#>empty]<#27149#> 
    <#27150#>[<#27150#><#27151#>else<#27151#> <#27152#>(c<#27152#><#27153#>ond<#27153#> 
            <#27154#>[<#27154#><#27155#>(<#27155#>#tex2html_wrap73222# <#27157#>(first<#27157#> <#27158#>aloir)<#27158#> <#27159#>t)<#27159#> 
             <#27160#>(<#27160#><#27161#>cons<#27161#> <#27162#>(first<#27162#> <#27163#>aloir)<#27163#> 
              <#27164#>(below-ir<#27164#> <#27165#>(rest<#27165#> <#27166#>aloir)<#27166#> <#27167#>t))]<#27167#> 
            <#27168#>[<#27168#><#27169#>e<#27169#><#27170#>lse<#27170#> 
              <#27171#>(below-ir<#27171#> <#27172#>(rest<#27172#> <#27173#>aloir)<#27173#> <#27174#>t)]<#27174#><#27175#>)]<#27175#><#27176#>))<#27176#> 

<#71251#>;; <#65056#>#tex2html_wrap_inline73210# <#27178#>:<#27178#> <#27179#>IR<#27179#> <#27180#>number<#27180#> <#27181#><#27181#><#27182#>-;SPMgt;<#27182#><#27183#><#27183#> <#27184#>boolean<#27184#><#65056#><#71251#> 
<#27185#>(def<#27185#><#27186#>ine<#27186#> <#27187#>(<#27187#>#tex2html_wrap_inline73212# <#27189#>ir<#27189#> <#27190#>p)<#27190#> 
    <#27191#>(;SPMlt;<#27191#> <#27192#>(ir-price<#27192#> <#27193#>ir)<#27193#> <#27194#>p))<#27194#> 
<#27198#>Figure: Marking the differences in similar functions<#27198#>
If we abstract the two functions, we obviously obtain <#65057#><#27200#>filter1<#27200#><#65057#>. Conversely, we can define <#65058#><#27201#>below-ir<#27201#><#65058#> in terms of <#65059#><#27202#>filter1<#27202#><#65059#>:
<#27207#>(d<#27207#><#27208#>efine<#27208#> <#27209#>(below-ir1<#27209#> <#27210#>aloir<#27210#> <#27211#>t)<#27211#>
  <#27212#>(filter1<#27212#> #tex2html_wrap_inline73214# <#27214#>aloir<#27214#> <#27215#>t))<#27215#> 
It should not surprise us to discover yet another use for <#65060#><#27219#>filter1<#27219#><#65060#>---after all, we already argued that abstraction promotes the re-use of functions for different purposes. Here we see that <#65061#><#27220#>filter1<#27220#><#65061#> not only filters lists of numbers but lists of arbitrary things---as long as we can define a function that compares these arbitrary things with numbers. Indeed, all we need is a function that compares items on the list with the items we pass to <#65062#><#27221#>filter1<#27221#><#65062#> as the second argument. Here is a function that extracts all items with the same label from a list of inventory records:
<#71252#>;; <#65063#><#27226#>find<#27226#> <#27227#>:<#27227#> <#27228#>loIR<#27228#> <#27229#>symbol<#27229#> <#27230#><#27230#><#27231#>-;SPMgt;<#27231#><#27232#><#27232#> <#27233#>boolean<#27233#><#65063#><#71252#>
<#71253#>;; to determine whether <#65064#><#27234#>aloir<#27234#><#65064#> contains a record for <#65065#><#27235#>t<#27235#><#65065#><#71253#> 
<#27236#>(d<#27236#><#27237#>efine<#27237#> <#27238#>(find<#27238#> <#27239#>aloir<#27239#> <#27240#>t)<#27240#> 
  <#27241#>(cons?<#27241#> <#27242#>(filter1<#27242#> <#27243#>eq-ir?<#27243#> <#27244#>aloir<#27244#> <#27245#>t)))<#27245#> 
<#71254#>;; <#65066#><#27246#>eq-ir?<#27246#> <#27247#>:<#27247#> <#27248#>IR<#27248#> <#27249#>symbol<#27249#> <#27250#><#27250#><#27251#>-;SPMgt;<#27251#><#27252#><#27252#> <#27253#>boolean<#27253#><#65066#><#71254#> 
<#71255#>;; to compare <#65067#><#27254#>ir<#27254#><#65067#>'s name and <#65068#><#27255#>p<#27255#><#65068#><#71255#> 
<#27256#>(d<#27256#><#27257#>efine<#27257#> <#27258#>(eq-ir?<#27258#> <#27259#>ir<#27259#> <#27260#>p)<#27260#> 
  <#27261#>(symbol=?<#27261#> <#27262#>(ir-name<#27262#> <#27263#>ir)<#27263#> <#27264#>p))<#27264#> 
This new relational operator compares the name in an inventory record with some other symbol.
<#27270#>Exercise 19.2.1<#27270#> Determine the values of
  1. <#65069#><#27273#>(below-ir1<#27273#>\ <#27274#>10<#27274#>\ <#27275#>(list<#27275#>\ <#27276#>(make-ir<#27276#>\ <#27277#>'<#27277#><#27278#>doll<#27278#>\ <#27279#>8)<#27279#>\ <#27280#>(make-ir<#27280#>\ <#27281#>'<#27281#><#27282#>robot<#27282#>\ <#27283#>12)))<#27283#><#65069#>
  2. <#65070#><#27284#>(find<#27284#>\ <#27285#>'<#27285#><#27286#>doll<#27286#>\ <#27287#>(list<#27287#>\ <#27288#>(make-ir<#27288#>\ <#27289#>'<#27289#><#27290#>doll<#27290#>\ <#27291#>8)<#27291#>\ <#27292#>(make-ir<#27292#>\ <#27293#>'<#27293#><#27294#>robot<#27294#>\ <#27295#>12)<#27295#>\ <#27296#>(make-ir<#27296#>\ <#27297#>'<#27297#><#27298#>doll<#27298#>\ <#27299#>13)))<#27299#><#65070#>
by hand and with DrScheme. Show only those lines that introduce new applications of <#65071#><#27301#>filter1<#27301#><#65071#> to values. external Solution<#65072#><#65072#>
In short, <#65073#><#27309#>filter1<#27309#><#65073#> uniformly works on many different shapes of input data. The word ``uniformly'' means that if <#65074#><#27310#>filter1<#27310#><#65074#> is applied to a list of <#65075#><#27311#>X<#27311#><#65075#>, its result is also a list of <#65076#><#27312#>X<#27312#><#65076#>---no matter what kind of Scheme data <#65077#><#27313#>X<#27313#><#65077#> is. Such functions are called <#65078#><#27314#>POLYMORPHIC<#27314#><#65078#> or <#65079#><#27315#>GENERIC<#27315#><#65079#> functions. Of course, <#65080#><#27316#>filter1<#27316#><#65080#> is not the only function that can process arbitrary lists. There are many other functions that process lists independently of what they contain. Here are two functions that determine the length of lists of numbers and <#65081#><#27317#>IR<#27317#><#65081#>s:
<#71256#>;; <#65082#><#27322#>length-lon<#27322#> <#27323#>:<#27323#> <#27324#>lon<#27324#> <#27325#><#27325#><#27326#>-;SPMgt;<#27326#><#27327#><#27327#> <#27328#>number<#27328#><#65082#><#71256#>
<#27329#>(d<#27329#><#27330#>efine<#27330#> <#27331#>(length-lon<#27331#> <#27332#>alon)<#27332#> 
  <#27333#>(c<#27333#><#27334#>ond<#27334#> 
    <#27335#>[<#27335#><#27336#>(empty?<#27336#> <#27337#>alon)<#27337#> <#27338#>empty]<#27338#> 
    <#27339#>[<#27339#><#27340#>e<#27340#><#27341#>lse<#27341#> 
      <#27342#>(+<#27342#> <#27343#>(length-lon<#27343#> <#27344#>(rest<#27344#> <#27345#>alon))<#27345#> <#27346#>1)]<#27346#><#27347#>))<#27347#> 
<#71257#>;; <#65083#><#27353#>length-ir<#27353#> <#27354#>:<#27354#> <#27355#>loIR<#27355#> <#27356#><#27356#><#27357#>-;SPMgt;<#27357#><#27358#><#27358#> <#27359#>number<#27359#><#65083#><#71257#>
<#27360#>(d<#27360#><#27361#>efine<#27361#> <#27362#>(length-ir<#27362#> <#27363#>alon)<#27363#> 
  <#27364#>(c<#27364#><#27365#>ond<#27365#> 
    <#27366#>[<#27366#><#27367#>(empty?<#27367#> <#27368#>alon)<#27368#> <#27369#>empty]<#27369#> 
    <#27370#>[<#27370#><#27371#>e<#27371#><#27372#>lse<#27372#> 
      <#27373#>(+<#27373#> <#27374#>(length-ir<#27374#> <#27375#>(rest<#27375#> <#27376#>alon))<#27376#> <#27377#>1)]<#27377#><#27378#>))<#27378#> 
The two functions only differ in their names. If we had chosen the same name, say <#65084#><#27382#>length<#27382#><#65084#>, the two definitions would be identical. To write precise contracts for functions such as <#65085#><#27383#>length<#27383#><#65085#>, we need <#27384#>parametric data definitions<#27384#>. A <#65086#><#27385#>PARAMETRIC DATA DEFINITION<#27385#><#65086#> does not specify all pieces of data; instead it uses variables to say that <#27386#> any<#27386#> form of Scheme data can be used in a certain place. Roughly speaking, a parametric data definition abstracts from a reference to a particular collection of data in the same manner as a function abstracts from a particular value. Here is a parametric definition of lists of <#65087#><#27387#>ITEM<#27387#><#65087#>s:
A <#65088#><#27389#>list of ITEM<#27389#><#65088#> is either
  1. <#65089#><#27391#>empty<#27391#><#65089#> or
  2. <#65090#><#27392#>(cons<#27392#>\ <#27393#>s<#27393#>\ <#27394#>l)<#27394#><#65090#> where
    1. <#65091#><#27396#>s<#27396#><#65091#> is #tex2html_wrap73224# and
    2. <#65092#><#27398#>l<#27398#><#65092#> is a list of ITEM.~
The token <#65093#><#27404#>ITEM<#27404#><#65093#> is a <#65094#><#27405#>TYPE VARIABLE<#27405#><#65094#> that stands for any arbitrary collection of Scheme data: symbols, numbers, booleans, <#65095#><#27406#>IR<#27406#><#65095#>s, etc. By replacing <#65096#><#27407#>ITEM<#27407#><#65096#> with one of these names, we get a concrete instance of this abstract data definition for lists of symbols, numbers, booleans, <#65097#><#27408#>IR<#27408#><#65097#>s, etc. To make the language of contracts more concise, we introduce an additional abbreviation:
<#27413#>(listof<#27413#> <#27414#>ITEM)<#27414#>
We use <#65098#><#27418#>(listof<#27418#>\ <#27419#>ITEM)<#27419#><#65098#> as the name of abstract data definitions like the above. In other words, we define <#65099#><#27420#>(listof<#27420#>\ <#27421#>ITEM)<#27421#><#65099#> as follows:
A <#72240#><#71258#><#65100#><#27423#>(listof<#27423#>\ <#27424#>ITEM)<#27424#><#65100#><#71258#><#72240#> is either
  1. <#65101#><#27426#>empty<#27426#><#65101#> or
  2. <#65102#><#27427#>(cons<#27427#>\ <#27428#>s<#27428#>\ <#27429#>l)<#27429#><#65102#> where
    1. <#65103#><#27431#>s<#27431#><#65103#> is #tex2html_wrap73226# and
    2. <#65105#><#27433#>l<#27433#><#65105#> is a <#65106#><#27434#>(listof<#27434#>\ <#27435#>ITEM)<#27435#><#65106#>.~
Then we can use <#65107#><#27441#>(listof<#27441#>\ <#27442#>symbol)<#27442#><#65107#> for the class of all lists of symbols, <#65108#><#27443#>(listof<#27443#>\ <#27444#>number)<#27444#><#65108#> for the class of all lists of numbers, <#65109#><#27445#>(listof<#27445#>\ <#27446#>(listof<#27446#>\ <#27447#>number))<#27447#><#65109#> for the class of all lists of lists of numbers, <#27448#>etc<#27448#>. In contracts, we use <#65110#><#27449#>(listof<#27449#>\ <#27450#>X)<#27450#><#65110#> to say that the function works on arbitrary lists:
<#71260#>;; <#65111#><#27455#>length<#27455#> <#27456#>:<#27456#> <#27457#>(listof<#27457#> <#27458#>X)<#27458#> <#27459#><#27459#><#27460#>-;SPMgt;<#27460#><#27461#><#27461#> <#27462#>number<#27462#><#65111#><#71260#>
<#27463#>;; to compute the length of a list <#27463#> 
<#27464#>(d<#27464#><#27465#>efine<#27465#> <#27466#>(length<#27466#> <#27467#>alon)<#27467#> 
  <#27468#>(c<#27468#><#27469#>ond<#27469#> 
    <#27470#>[<#27470#><#27471#>(empty?<#27471#> <#27472#>alon)<#27472#> <#27473#>empty]<#27473#> 
    <#27474#>[<#27474#><#27475#>else<#27475#> <#27476#>(+<#27476#> <#27477#>(length<#27477#> <#27478#>(rest<#27478#> <#27479#>alon))<#27479#> <#27480#>1)]<#27480#><#27481#>))<#27481#> 
The <#65112#><#27485#>X<#27485#><#65112#> is just a variable, a name that stands for some class of data. If we now apply <#65113#><#27486#>length<#27486#><#65113#> to an element of, say, <#65114#><#27487#>(listof<#27487#>\ <#27488#>symbol)<#27488#><#65114#> or <#65115#><#27489#>(listof<#27489#>\ <#27490#>IR)<#27490#><#65115#>, we get a number. The function <#65116#><#27491#>length<#27491#><#65116#> is an example of simple polymorphism. It works on all classes of lists. While there are other useful examples of simple polymorphic functions, the more common cases require that we define functions like <#65117#><#27492#>filter1<#27492#><#65117#>, which consume a parametric form of data and functions that work on this data. This combination is extremely powerful and greatly facilitates the construction and maintenance of software systems. To understand it better, we will next discuss a revision of Scheme's grammar and new ways to write contracts.
<#27495#>Exercise 19.2.2<#27495#> Show how to use the abstracted version of <#65118#><#27497#>sort<#27497#><#65118#> from exercise~#exabssort#27498> to sort a list of <#65119#><#27499#>IR<#27499#><#65119#>s in ascending and descending order. external Solution<#65120#><#65120#> <#27505#>Exercise 19.2.3<#27505#> Here is a structure definition for pairs
<#27511#>(define-struct<#27511#> <#27512#>pair<#27512#> <#27513#>(left<#27513#> <#27514#>right))<#27514#>
and its parametric data definition:
A <#72241#><#71261#>(pair <#65121#><#27519#>X<#27519#><#65121#> <#65122#><#27520#>Y<#27520#><#65122#>)<#71261#><#72241#> is a structure:

<#71262#><#65123#><#27521#>(make-pair<#27521#>\ <#27522#>l<#27522#>\ <#27523#>r)<#27523#><#65123#><#71262#> where <#65124#><#27524#>l<#27524#><#65124#> is an <#65125#><#27525#>X<#27525#><#65125#> and <#65126#><#27526#>r<#27526#><#65126#> is a <#65127#><#27527#>Y<#27527#><#65127#>.

Using this abstract data definition, we can describe many different forms of pairs:
  1. <#65128#><#27530#>(pair<#27530#>\ <#27531#>number<#27531#>\ <#27532#>number)<#27532#><#65128#>, which is the class of pairs that combine two numbers;
  2. <#65129#><#27533#>(pair<#27533#>\ <#27534#>symbol<#27534#>\ <#27535#>number)<#27535#><#65129#>, which is the class of pairs that combine a number with a symbol; and
  3. <#65130#><#27536#>(pair<#27536#>\ <#27537#>symbol<#27537#>\ <#27538#>symbol)<#27538#><#65130#>, which is the class of pairs that combine two symbols.
Still, in all of these examples, each pair contains two values that are accessible via <#65131#><#27540#>pair-left<#27540#><#65131#> and <#65132#><#27541#>pair-right<#27541#><#65132#>. By combining the abstract data definition for lists and pairs we can describe lists of parametric pairs with a single line:

<#71263#> <#65133#><#27542#>(listof<#27542#>\ <#27543#>(pair<#27543#>\ <#27544#>X<#27544#>\ <#27545#>Y))<#27545#><#65133#> \ .<#71263#> Some concrete examples of this abstract class of data are:

  1. <#65134#><#27547#>(listof<#27547#>\ <#27548#>(pair<#27548#>\ <#27549#>number<#27549#>\ <#27550#>number))<#27550#><#65134#>, the list of pairs of numbers;
  2. <#65135#><#27551#>(listof<#27551#>\ <#27552#>(pair<#27552#>\ <#27553#>symbol<#27553#>\ <#27554#>number))<#27554#><#65135#>, the list of pairs of symbols and numbers;
  3. <#65136#><#27555#>(listof<#27555#>\ <#27556#>(pair<#27556#>\ <#27557#>symbol<#27557#>\ <#27558#>symbol))<#27558#><#65136#>, the list of pairs of symbols.
Make an example for each of these classes. Develop the function <#65137#><#27560#>lefts<#27560#><#65137#>, which consumes a list of <#65138#><#27561#>(pair<#27561#>\ <#27562#>X<#27562#>\ <#27563#>Y)<#27563#><#65138#> and produces a corresponding list of <#65139#><#27564#>X<#27564#><#65139#>'s; that is, it extracts the <#65140#><#27565#>left<#27565#><#65140#> part of each item in its input.~ external Solution<#65141#><#65141#> <#27571#>Exercise 19.2.4<#27571#> Here is a parametric data definition of non-empty lists:
<#72343#>A <#72242#><#71264#><#65142#><#27574#>(non-empty-listof<#27574#>\ <#27575#>ITEM)<#27575#><#65142#><#71264#><#72242#> is either
  1. <#65143#><#27577#>(cons<#27577#>\ <#27578#>s<#27578#>\ <#27579#>empty)<#27579#><#65143#>, or
  2. <#65144#><#27580#>(cons<#27580#>\ <#27581#>s<#27581#>\ <#27582#>l)<#27582#><#65144#> where <#65145#><#27583#>l<#27583#><#65145#> is a <#65146#><#27584#>(non-empty-listof<#27584#>\ <#27585#>ITEM)<#27585#><#65146#>
<#72343#> and <#65147#><#27587#>s<#27587#><#65147#> is always an <#65148#><#27588#>ITEM<#27588#><#65148#>.
Develop the function <#65149#><#27590#>last<#27590#><#65149#>, which consumes a <#65150#><#27591#>(non-empty-listof<#27591#>\ <#27592#>ITEM)<#27592#><#65150#> and produces the last <#65151#><#27593#>ITEM<#27593#><#65151#> in that list. <#27594#>Hint:<#27594#> \ Replace <#65152#><#27595#>ITEM<#27595#><#65152#> with a fixed class of data to develop an initial draft of <#65153#><#27596#>last<#27596#><#65153#>. When finished, replace the class with <#65154#><#27597#>ITEM<#27597#><#65154#> throughout the function development.~ external Solution<#65155#><#65155#>