Processing Two Lists Simultaneously: Case 2

In section~#seclistproduce#19696>, we developed the function <#71129#><#19697#>hours<#19697#><#64099#><#19698#><#19698#><#19699#>-;SPMgt;<#19699#><#19700#><#19700#><#64099#><#19701#>wages<#19701#><#71129#> for the computation of weekly wages. It consumed a list of numbers---hours worked per week---and produced a list of weekly wages. We had based the function on the simplifying assumption that all employees received the same pay rate. Even a small company, however, employs people at different rate levels. Typically, the company's accountant also maintains two collections of information: a permanent one that, among other things, includes an employee's personal pay-rate, and a temporary one that records how much time an employee has worked during the past week. The revised problem statement means that the function should consume <#19702#>two<#19702#> lists. To simplify the problem, let us assume that the lists are just lists of numbers, pay rates and weekly hours. Then here is the problem statement:
<#72223#>;; <#71130#><#19707#>hours<#19707#><#64100#><#19708#><#19708#><#19709#>-;SPMgt;<#19709#><#19710#><#19710#><#64100#><#19711#>wages<#19711#> <#19712#>:<#19712#> <#19713#>list-of-numbers<#19713#> <#19714#>list-of-numbers<#19714#> <#19715#><#19715#><#19716#>-;SPMgt;<#19716#><#19717#><#19717#> <#19718#>list-of-numbers<#19718#><#71130#><#72223#>
<#19719#>;; to construct a new list by multiplying the corresponding items on<#19719#> 
<#71131#>;; <#64101#><#19720#>alon1<#19720#><#64101#> and <#64102#><#19721#>alon2<#19721#><#64102#><#71131#> 
<#64103#>;; <#19722#>ASSUMPTION<#19722#>: the two lists are of equal length <#64103#> 
<#19723#>(define<#19723#> <#19724#>(<#19724#><#19725#>hours<#19725#><#64104#><#19726#><#19726#><#19727#>-;SPMgt;<#19727#><#19728#><#19728#><#64104#><#19729#>wages<#19729#> <#19730#>alon1<#19730#> <#19731#>alon2)<#19731#> <#19732#>...)<#19732#> 
We can think of <#64105#><#19736#>alon1<#19736#><#64105#> as the list of pay-rates and of <#64106#><#19737#>alon2<#19737#><#64106#> as the list of hours worked per week. To get the list of weekly wages, we must multiply the corresponding numbers in the two input lists. Let's look at some examples:
  <#19742#>(<#19742#><#19743#>hours<#19743#><#64107#><#19744#><#19744#><#19745#>-;SPMgt;<#19745#><#19746#><#19746#><#64107#><#19747#>wages<#19747#> <#19748#>empty<#19748#> <#19749#>empty)<#19749#>
<#19750#>=<#19750#> <#19751#>empty<#19751#> 
  <#19759#>(<#19759#><#19760#>hours<#19760#><#64108#><#19761#><#19761#><#19762#>-;SPMgt;<#19762#><#19763#><#19763#><#64108#><#19764#>wages<#19764#> <#19765#>(cons<#19765#> <#19766#>5.65<#19766#> <#19767#>empty)<#19767#> 
                      <#19768#>(cons<#19768#> <#19769#>40<#19769#> <#19770#>empty))<#19770#> 
<#19771#>=<#19771#> <#19772#>(cons<#19772#> <#19773#>226.0<#19773#> <#19774#>empty)<#19774#> 
  <#19782#>(<#19782#><#19783#>hours<#19783#><#64109#><#19784#><#19784#><#19785#>-;SPMgt;<#19785#><#19786#><#19786#><#64109#><#19787#>wages<#19787#> <#19788#>(cons<#19788#> <#19789#>5.65<#19789#> <#19790#>(cons<#19790#> <#19791#>8.75<#19791#> <#19792#>empty))<#19792#> 
                      <#19793#>(cons<#19793#> <#19794#>40<#19794#> <#19795#>(cons<#19795#> <#19796#>30<#19796#> <#19797#>empty)))<#19797#> 
<#19798#>=<#19798#> <#19799#>(cons<#19799#> <#19800#>226.0<#19800#> <#19801#>(cons<#19801#> <#19802#>262.5<#19802#> <#19803#>empty))<#19803#> 
For all three examples the function is applied to two lists of equal length. As stated in the addendum to the purpose statement, the function assumes this and, indeed, using the function makes no sense if the condition is violated. The condition on the inputs can also be exploited for the development of the template. Put more concretely, the condition says that <#64110#><#19807#>(empty?<#19807#><#19808#> <#19808#><#19809#>alon1)<#19809#><#64110#> is true if, and only if, <#64111#><#19810#>(empty?<#19810#>\ <#19811#>alon2)<#19811#><#64111#> is true; and furthermore, <#64112#><#19812#>(cons?<#19812#>\ <#19813#>alon1)<#19813#><#64112#> is true if, and only if, <#64113#><#19814#>(cons?<#19814#><#19815#> <#19815#><#19816#>alon2)<#19816#><#64113#> is true. In other words, the condition simplifies the design of the template's <#64114#><#19817#>cond<#19817#><#64114#>-structure, because it says the template is similar to that of a plain list-processing function:
<#19822#>(d<#19822#><#19823#>efine<#19823#> <#19824#>(<#19824#><#19825#>hours<#19825#><#64115#><#19826#><#19826#><#19827#>-;SPMgt;<#19827#><#19828#><#19828#><#64115#><#19829#>wages<#19829#> <#19830#>alon1<#19830#> <#19831#>alon2)<#19831#>
  <#19832#>(c<#19832#><#19833#>ond<#19833#> 
    <#19834#>((empty?<#19834#> <#19835#>alon1)<#19835#> <#19836#>...)<#19836#> 
    <#19837#>(else<#19837#> <#19838#>...<#19838#> <#19839#>)))<#19839#> 
In the first <#64116#><#19843#>cond<#19843#><#64116#>-clause, both <#64117#><#19844#>alon1<#19844#><#64117#> and <#64118#><#19845#>alon2<#19845#><#64118#> are <#64119#><#19846#>empty<#19846#><#64119#>. Hence, no selector expressions are needed. In the second clause, both <#64120#><#19847#>alon1<#19847#><#64120#> and <#64121#><#19848#>alon2<#19848#><#64121#> are <#64122#><#19849#>cons<#19849#><#64122#>tructed lists, which means we need four selector expressions:
<#19854#>(d<#19854#><#19855#>efine<#19855#> <#19856#>(<#19856#><#19857#>hours<#19857#><#64123#><#19858#><#19858#><#19859#>-;SPMgt;<#19859#><#19860#><#19860#><#64123#><#19861#>wages<#19861#> <#19862#>alon1<#19862#> <#19863#>alon2)<#19863#>
  <#19864#>(c<#19864#><#19865#>ond<#19865#> 
    <#19866#>((empty?<#19866#> <#19867#>alon1)<#19867#> <#19868#>...)<#19868#> 
    <#19869#>(e<#19869#><#19870#>lse<#19870#> 
      <#19871#>...<#19871#> <#19872#>(first<#19872#> <#19873#>alon1)<#19873#> <#19874#>...<#19874#> <#19875#>(first<#19875#> <#19876#>alon2)<#19876#> <#19877#>...<#19877#> 
      <#19878#>...<#19878#> <#19879#>(rest<#19879#> <#19880#>alon1)<#19880#> <#19881#>...<#19881#> <#19882#>(rest<#19882#> <#19883#>alon2)<#19883#> <#19884#>...<#19884#> <#19885#>)))<#19885#> 
Finally, because the last two are lists of equal length, they make up a natural candidate for the natural recursion of <#71132#><#19889#>hours<#19889#><#64124#><#19890#><#19890#><#19891#>-;SPMgt;<#19891#><#19892#><#19892#><#64124#><#19893#>wages<#19893#><#71132#>:
<#19898#>(d<#19898#><#19899#>efine<#19899#> <#19900#>(<#19900#><#19901#>hours<#19901#><#64125#><#19902#><#19902#><#19903#>-;SPMgt;<#19903#><#19904#><#19904#><#64125#><#19905#>wages<#19905#> <#19906#>alon1<#19906#> <#19907#>alon2)<#19907#>
  <#19908#>(c<#19908#><#19909#>ond<#19909#> 
    <#19910#>((empty?<#19910#> <#19911#>alon1)<#19911#> <#19912#>...)<#19912#> 
    <#19913#>(e<#19913#><#19914#>lse<#19914#> 
      <#19915#>...<#19915#> <#19916#>(first<#19916#> <#19917#>alon1)<#19917#> <#19918#>...<#19918#> <#19919#>(first<#19919#> <#19920#>alon2)<#19920#> <#19921#>...<#19921#> 
      <#19922#>...<#19922#> <#19923#>(<#19923#><#19924#>hours<#19924#><#64126#><#19925#><#19925#><#19926#>-;SPMgt;<#19926#><#19927#><#19927#><#64126#><#19928#>wages<#19928#> <#19929#>(rest<#19929#> <#19930#>alon1)<#19930#> <#19931#>(rest<#19931#> <#19932#>alon2))<#19932#> <#19933#>...<#19933#> <#19934#>)))<#19934#> 
The only unusual aspect of this template is that the recursive application consists of two expressions, both selector expressions for the two arguments. But, as we have seen, the idea is easily explicable due to the assumption that <#64127#><#19938#>alon1<#19938#><#64127#> and <#64128#><#19939#>alon2<#19939#><#64128#> are of equal length.
<#72224#>;; <#71133#><#19944#>hours<#19944#><#64129#><#19945#><#19945#><#19946#>-;SPMgt;<#19946#><#19947#><#19947#><#64129#><#19948#>wages<#19948#> <#19949#>:<#19949#> <#19950#>list-of-numbers<#19950#> <#19951#>list-of-numbers<#19951#> <#19952#><#19952#><#19953#>-;SPMgt;<#19953#><#19954#><#19954#> <#19955#>list-of-numbers<#19955#><#71133#><#72224#>
<#19956#>;; to construct a new list by multiplying the corresponding items on<#19956#> 
<#64130#>;; <#19957#>ASSUMPTION<#19957#>: the two lists are of equal length <#64130#> 
<#71134#>;; <#64131#><#19958#>alon1<#19958#><#64131#> and <#64132#><#19959#>alon2<#19959#><#64132#><#71134#> 
<#19960#>(d<#19960#><#19961#>efine<#19961#> <#19962#>(<#19962#><#19963#>hours<#19963#><#64133#><#19964#><#19964#><#19965#>-;SPMgt;<#19965#><#19966#><#19966#><#64133#><#19967#>wages<#19967#> <#19968#>alon1<#19968#> <#19969#>alon2)<#19969#> 
  <#19970#>(c<#19970#><#19971#>ond<#19971#> 
    <#19972#>((empty?<#19972#> <#19973#>alon1)<#19973#> <#19974#>empty)<#19974#> 
    <#19975#>(else<#19975#> <#19976#>(cons<#19976#> <#19977#>(weekly-wage<#19977#> <#19978#>(first<#19978#> <#19979#>alon1)<#19979#> <#19980#>(first<#19980#> <#19981#>alon2))<#19981#> 
                <#19982#>(<#19982#><#19983#>hours<#19983#><#64134#><#19984#><#19984#><#19985#>-;SPMgt;<#19985#><#19986#><#19986#><#64134#><#19987#>wages<#19987#> <#19988#>(rest<#19988#> <#19989#>alon1)<#19989#> <#19990#>(rest<#19990#> <#19991#>alon2))))))<#19991#> 
<#71135#>;; <#64135#><#19992#>weekly-wage<#19992#> <#19993#>:<#19993#> <#19994#>number<#19994#> <#19995#>number<#19995#> <#19996#><#19996#><#19997#>-;SPMgt;<#19997#><#19998#><#19998#> <#19999#>number<#19999#><#64135#><#71135#> 
<#71136#>;; to compute the weekly wage from <#64136#><#20000#>pay-rate<#20000#><#64136#> and <#64137#><#20001#>hours-worked<#20001#><#64137#><#71136#> 
<#20002#>(d<#20002#><#20003#>efine<#20003#> <#20004#>(weekly-wage<#20004#> <#20005#>pay-rate<#20005#> <#20006#>hours-worked)<#20006#> 
  <#20007#>(*<#20007#> <#20008#>pay-rate<#20008#> <#20009#>hours-worked))<#20009#> 
<#64138#>Figure: The complete definition of <#20013#>hours<#20013#>#tex2html_wrap_inline73080#<#20014#>wage<#20014#><#64138#>
To define the function from here, we follow the design recipe. The first example implies that the answer for the first <#64139#><#20016#>cond<#20016#><#64139#>-clause is <#64140#><#20017#>empty<#20017#><#64140#>. In the second one, we have three values available:
  1. <#64141#><#20019#>(first<#20019#>\ <#20020#>alon1)<#20020#><#64141#> evaluates to the first item on the list of pay-rates;
  2. <#64142#><#20021#>(first<#20021#>\ <#20022#>alon2)<#20022#><#64142#> evaluates to the first item on the list of hours worked; and
  3. <#71137#><#20023#>(<#20023#><#20024#>hours<#20024#><#64143#><#20025#><#20025#><#20026#>-;SPMgt;<#20026#><#20027#><#20027#><#64143#><#20028#>wages<#20028#>\ <#20029#>(rest<#20029#>\ <#20030#>alon1)<#20030#>\ <#20031#>(rest<#20031#>\ <#20032#>alon2))<#20032#><#71137#> computes the list of weekly wages for the remainders of <#64144#><#20033#>alon1<#20033#><#64144#> and <#64145#><#20034#>alon2<#20034#><#64145#>.
We merely need to combine these values to get the final answer. More specifically, given the purpose statement, we must compute the weekly wage for the first employee and <#64146#><#20036#>cons<#20036#><#64146#>truct a list from that wage and the rest of the wages. This suggests the following answer for the second <#64147#><#20037#>cond<#20037#><#64147#>-clause:
<#20042#>(cons<#20042#> <#20043#>(weekly-wage<#20043#> <#20044#>(first<#20044#> <#20045#>alon1)<#20045#> <#20046#>(first<#20046#> <#20047#>alon2))<#20047#>
      <#20048#>(<#20048#><#20049#>hours<#20049#><#64148#><#20050#><#20050#><#20051#>-;SPMgt;<#20051#><#20052#><#20052#><#64148#><#20053#>wages<#20053#> <#20054#>(rest<#20054#> <#20055#>alon1)<#20055#> <#20056#>(rest<#20056#> <#20057#>alon2)))<#20057#> 
The auxiliary function <#64149#><#20061#>weekly-wage<#20061#><#64149#> consumes the two first items and computes the weekly wage. Figure~#fighourswage#20062> contains the complete definitions.
<#20065#>Exercise 17.2.1<#20065#> In the real world, <#71138#><#20067#>hours<#20067#><#64150#><#20068#><#20068#><#20069#>-;SPMgt;<#20069#><#20070#><#20070#><#64150#><#20071#>wages<#20071#><#71138#> consumes lists of employee structures and lists of work structures. An employee structure contains an employee's name, social security number, and pay rate. A work structure contains an employee's name and the number of hours worked in a week. The result is a list of structures that contain the name of the employee and the weekly wage. Modify the function in figure~#fighourswage#20072> so that it works on these classes of data. Provide the necessary structure definitions and data definitions. Use the design recipe to guide the modification process.~ external Solution<#64151#><#64151#> <#20078#>Exercise 17.2.2<#20078#> Develop the function <#64152#><#20080#>zip<#20080#><#64152#>, which combines a list of names and a list phone numbers into a list of phone records. Assuming the following structure definition:
<#20085#>(define-struct<#20085#> <#20086#>phone-record<#20086#> <#20087#>(name<#20087#> <#20088#>number))<#20088#> <#20089#>,<#20089#>
a phone record is constructed with <#64153#><#20093#>(make-phone-record<#20093#>\ <#20094#>s<#20094#>\ <#20095#>n)<#20095#><#64153#> where <#64154#><#20096#>s<#20096#><#64154#> is a symbol and <#64155#><#20097#>n<#20097#><#64155#> is a number. Assume the lists are of equal length. Simplify the definition, if possible. external Solution<#64156#><#64156#>