Recursive Auxiliary Functions

#drnsecsortI#13867> People need to sort things all the time. Investment advisors sort portfolios by the profit each holding generates. Doctors sort lists of transplant patients. Mail programs sort messages. More generally, sorting lists of values by some criteria is a task that many programs need to perform. Here we study how to sort a list of numbers because it is important for many programming tasks, but also because it provides a good case study concerning the design of auxiliary programs. A sorting function consumes a list and produces one. Indeed, the two lists contains the same numbers, though the output list contains them in a different order. This is the essence of the contract and purpose statement:
 
<#71017#>;; <#62942#><#13872#>sort<#13872#> <#13873#>:<#13873#> <#13874#>list-of-numbers<#13874#> <#13875#><#13875#><#13876#>-;SPMgt;<#13876#><#13877#><#13877#> <#13878#>list-of-numbers<#13878#><#62942#> <#71017#> 
<#71018#>;; to create sorted list of numbers from all the numbers in <#62943#><#13879#>alon<#13879#><#62943#><#71018#> 
<#13880#>(define<#13880#> <#13881#>(sort<#13881#> <#13882#>alon)<#13882#> <#13883#>...)<#13883#> 
Here is one example per clause in the data definition:
  <#13891#>(sort<#13891#> <#13892#>empty)<#13892#>
<#13893#>=<#13893#> <#13894#>empty<#13894#> 
  <#13902#>(sort<#13902#> <#13903#>(cons<#13903#> <#13904#>1297.04<#13904#> <#13905#>(cons<#13905#> <#13906#>20000.00<#13906#> <#13907#>(cons<#13907#> <#13908#>-505.25<#13908#> <#13909#>empty))))<#13909#>
<#13910#>=<#13910#> <#13911#>(cons<#13911#> <#13912#>20000.00<#13912#> <#13913#>(cons<#13913#> <#13914#>1297.04<#13914#> <#13915#>(cons<#13915#> <#13916#>-505.25<#13916#> <#13917#>empty)))<#13917#> 
The answer for the input <#62944#><#13921#>empty<#13921#><#62944#> is <#62945#><#13922#>empty<#13922#><#62945#>, because <#62946#><#13923#>empty<#13923#><#62946#> contains the same items (none) and in sorted order. Next we must translate the data definition into a function template. Again, we have dealt with lists of numbers before, so this step is easy:
<#13928#>(d<#13928#><#13929#>efine<#13929#> <#13930#>(sort<#13930#> <#13931#>alon)<#13931#>
  <#13932#>(c<#13932#><#13933#>ond<#13933#> 
    <#13934#>[<#13934#><#13935#>(empty?<#13935#> <#13936#>alon)<#13936#> <#13937#>...]<#13937#> 
    <#13938#>[<#13938#><#13939#>else<#13939#> <#13940#>...<#13940#> <#13941#>(first<#13941#> <#13942#>alon)<#13942#> <#13943#>...<#13943#> <#13944#>(sort<#13944#> <#13945#>(rest<#13945#> <#13946#>alon))<#13946#> <#13947#>...]<#13947#><#13948#>))<#13948#> 
Using this template, we can finally turn to the interesting part of the program development. We consider each case of the <#62947#><#13952#>cond<#13952#>-expression<#62947#> separately, starting with the simple case. If <#62948#><#13953#>sort<#13953#><#62948#>'s input is <#62949#><#13954#>empty<#13954#><#62949#>, then the answer is <#62950#><#13955#>empty<#13955#><#62950#>, as specified by the example. So let's assume that the input is not <#62951#><#13956#>empty<#13956#><#62951#>. That is, let's deal with the second <#62952#><#13957#>cond<#13957#><#62952#>-clause. It contains two expressions and, following the design recipe, we must understand what they compute:
  1. <#62953#><#13959#>(first<#13959#>\ <#13960#>alon)<#13960#><#62953#> extracts the first number from the input;
  2. <#62954#><#13961#>(sort<#13961#>\ <#13962#>(rest<#13962#>\ <#13963#>alon))<#13963#><#62954#> produces a sorted version of <#62955#><#13964#>(rest<#13964#>\ <#13965#>alon)<#13965#><#62955#>, according to the purpose statement of the function.
Putting together these two values means to insert the first number into its appropriate spot in the sorted rest of the list. Let's look at the second example in this context. When <#62956#><#13967#>sort<#13967#><#62956#> consumes <#62957#><#13968#>(cons<#13968#>\ <#13969#>1297.04<#13969#>\ <#13970#>(cons<#13970#>\ <#13971#>20000.00<#13971#>\ <#13972#>(cons<#13972#>\ <#13973#>-505.25<#13973#>\ <#13974#>empty)))<#13974#><#62957#>, then
  1. <#62958#><#13976#>(first<#13976#>\ <#13977#>alon)<#13977#><#62958#> evaluates to <#62959#><#13978#>1297.04<#13978#><#62959#>,
  2. <#62960#><#13979#>(rest<#13979#>\ <#13980#>alon)<#13980#><#62960#> is <#62961#><#13981#>(cons<#13981#>\ <#13982#>20000.00<#13982#>\ <#13983#>(cons<#13983#>\ <#13984#>-505.25<#13984#>\ <#13985#>empty))<#13985#><#62961#>, and
  3. <#62962#><#13986#>(sort<#13986#>\ <#13987#>(rest<#13987#>\ <#13988#>alon))<#13988#><#62962#> produces <#62963#><#13989#>(cons<#13989#>\ <#13990#>20000.00<#13990#>\ <#13991#>(cons<#13991#>\ <#13992#>-505.25<#13992#>\ <#13993#>empty))<#13993#><#62963#>.
To produce the desired answer, we must insert <#62964#><#13995#>1297.04<#13995#><#62964#> in between the two numbers of the last list. More generally, the answer in the second <#62965#><#13996#>cond<#13996#><#62965#>-line must be an expression that inserts <#62966#><#13997#>(first<#13997#><#13998#> <#13998#>\ <#13999#>alon)<#13999#><#62966#> into its proper place into the sorted list <#62967#><#14000#>(sort<#14000#>\ <#14001#>(rest<#14001#><#14002#> <#14002#>\ <#14003#>alon))<#14003#><#62967#>. Insert a number into a sorted list isn't a simple task. We may have to search through the entire list before we know what the proper place is. Searching through a list, however, can only be done with a function, because lists are of arbitrary size and processing such values requires recursive functions. Thus we must develop an auxiliary function that consumes the first number and a sorted list and create a sorted list from both. Let us call this function <#62968#><#14004#>insert<#14004#><#62968#> and let us formulate a wish-list entry:
<#71019#>;; <#62969#><#14009#>insert<#14009#> <#14010#>:<#14010#> <#14011#>number<#14011#> <#14012#>list-of-numbers<#14012#> <#14013#><#14013#><#14014#>-;SPMgt;<#14014#><#14015#><#14015#> <#14016#>list-of-numbers<#14016#><#62969#><#71019#>
<#71020#>;; to create a list of numbers from <#62970#><#14017#>n<#14017#><#62970#> and the numbers on <#62971#><#14018#>alon<#14018#><#62971#> <#71020#> 
<#71021#>;; that is sorted in descending order; <#62972#><#14019#>alon<#14019#><#62972#> is already sorted<#71021#> 
<#14020#>(define<#14020#> <#14021#>(insert<#14021#> <#14022#>n<#14022#> <#14023#>alon)<#14023#> <#14024#>...)<#14024#> 
Using <#62973#><#14028#>insert<#14028#><#62973#>, it is easy to complete the definition of <#62974#><#14029#>sort<#14029#><#62974#>:
<#14034#>(d<#14034#><#14035#>efine<#14035#> <#14036#>(sort<#14036#> <#14037#>alon)<#14037#>
  <#14038#>(c<#14038#><#14039#>ond<#14039#> 
    <#14040#>[<#14040#><#14041#>(empty?<#14041#> <#14042#>alon)<#14042#> <#14043#>empty]<#14043#> 
    <#14044#>[<#14044#><#14045#>else<#14045#> <#14046#>(insert<#14046#> <#14047#>(first<#14047#> <#14048#>alon)<#14048#> <#14049#>(sort<#14049#> <#14050#>(rest<#14050#> <#14051#>alon)))]<#14051#><#14052#>))<#14052#> 
The answer in the second line says that in order to produce the final result, <#62975#><#14056#>sort<#14056#><#62975#> extracts the first item of the non-empty list, computes the sorted version of the rest of the list, and <#62976#><#14057#>insert<#14057#><#62976#>s the former into the latter at its appropriate place. Of course, we are not really finished until we have developed <#62977#><#14058#>insert<#14058#><#62977#>. We already have a contract, a header and a purpose statement. Next we need to make up function examples. Since the first input of <#62978#><#14059#>insert<#14059#><#62978#> is atomic, let's make up examples based on the data definition for lists. That is, we first consider what <#62979#><#14060#>insert<#14060#><#62979#> should produce when given a number and <#62980#><#14061#>empty<#14061#><#62980#>. According to <#62981#><#14062#>insert<#14062#><#62981#>'s purpose statement, the output must be a list, it must contain all numbers from the second input, and it must contain the first argument. This suggests the following:
  <#14067#>(insert<#14067#> <#14068#>5<#14068#> <#14069#>empty)<#14069#>
<#14070#>=<#14070#> <#14071#>(cons<#14071#> <#14072#>5<#14072#> <#14073#>empty)<#14073#> 
Instead of <#62982#><#14077#>5<#14077#><#62982#>, we could have used any number. The second example must use a non-empty list, but then, the idea for <#62983#><#14078#>insert<#14078#><#62983#> was suggested by just such an example when we studied how <#62984#><#14079#>sort<#14079#><#62984#> should deal with non-empty lists. Specifically, we said that <#62985#><#14080#>sort<#14080#><#62985#> had to insert <#62986#><#14081#>1297.04<#14081#><#62986#> into <#62987#><#14082#>(cons<#14082#>\ <#14083#>20000.00<#14083#><#14084#> <#14084#><#14085#>(cons<#14085#>\ <#14086#>-505.25<#14086#>\ <#14087#>empty))<#14087#><#62987#> at its proper place:
  <#14092#>(insert<#14092#> <#14093#>1297.04<#14093#> <#14094#>(cons<#14094#> <#14095#>20000.00<#14095#> <#14096#>(cons<#14096#> <#14097#>-505.25<#14097#> <#14098#>empty)))<#14098#>
<#14099#>=<#14099#> <#14100#>(cons<#14100#> <#14101#>20000.00<#14101#> <#14102#>(cons<#14102#> <#14103#>1297.04<#14103#> <#14104#>(cons<#14104#> <#14105#>-505.25<#14105#> <#14106#>empty)))<#14106#> 
In contrast to <#62988#><#14110#>sort<#14110#><#62988#>, the function <#62989#><#14111#>insert<#14111#><#62989#> consumes <#14112#>two<#14112#> inputs. But we know that the first one is a number and atomic. We can therefore focus on the second argument, which is a list of numbers and which suggests that we use the list-processing template one more time:
<#14117#>(d<#14117#><#14118#>efine<#14118#> <#14119#>(insert<#14119#> <#14120#>n<#14120#> <#14121#>alon)<#14121#>
  <#14122#>(c<#14122#><#14123#>ond<#14123#> 
    <#14124#>[<#14124#><#14125#>(empty?<#14125#> <#14126#>alon)<#14126#> <#14127#>...]<#14127#> 
    <#14128#>[<#14128#><#14129#>else<#14129#>  <#14130#>...<#14130#>  <#14131#>(first<#14131#> <#14132#>alon)<#14132#> <#14133#>...<#14133#> <#14134#>(insert<#14134#> <#14135#>n<#14135#> <#14136#>(rest<#14136#> <#14137#>alon))<#14137#> <#14138#>...]<#14138#><#14139#>))<#14139#> 
The only difference between this template and the one for <#62990#><#14143#>sort<#14143#><#62990#> is that this one needs to take into account the additional argument <#62991#><#14144#>n<#14144#><#62991#>. To fill the gaps in the template of <#62992#><#14145#>insert<#14145#><#62992#>, we again proceed on a case-by-case basis. The first case concerns the empty list. According to the purpose statement, <#62993#><#14146#>insert<#14146#><#62993#> must now construct a list with one number: <#62994#><#14147#>n<#14147#><#62994#>. Hence, the answer in the first case is <#62995#><#14148#>(cons<#14148#>\ <#14149#>n<#14149#><#14150#> <#14150#>\ <#14151#>alon)<#14151#><#62995#>. The second case is more complicated than that. When <#62996#><#14152#>alon<#14152#><#62996#> is not empty,
  1. <#62997#><#14154#>(first<#14154#>\ <#14155#>alon)<#14155#><#62997#> is the first number on <#62998#><#14156#>alon<#14156#><#62998#> and
  2. <#62999#><#14157#>(insert<#14157#>\ <#14158#>n<#14158#>\ <#14159#>(rest<#14159#>\ <#14160#>alon))<#14160#><#62999#> produces a sorted list consisting of <#63000#><#14161#>n<#14161#><#63000#> and all numbers on <#63001#><#14162#>(rest<#14162#>\ <#14163#>alon)<#14163#><#63001#>.
The problem is how to combine these pieces of data to get the answer. Let us consider an example:
<#14169#>(insert<#14169#> <#14170#>3<#14170#> <#14171#>(cons<#14171#> <#14172#>4<#14172#> <#14173#>(cons<#14173#> <#14174#>5<#14174#> <#14175#>(cons<#14175#> <#14176#>6<#14176#> <#14177#>empty))))<#14177#>
Here <#63002#><#14181#>n<#14181#><#63002#> is <#63003#><#14182#>3<#14182#><#63003#> and smaller than any of the numbers in the second input. Hence, it suffices if we just <#63004#><#14183#>cons<#14183#><#63004#> <#63005#><#14184#>3<#14184#><#63005#> onto <#63006#><#14185#>(cons<#14185#>\ <#14186#>4<#14186#>\ <#14187#>(cons<#14187#>\ <#14188#>5<#14188#>\ <#14189#>(cons<#14189#>\ <#14190#>6<#14190#>\ <#14191#>empty)))<#14191#><#63006#>. In contrast, when the application is something like
<#14196#>(insert<#14196#> <#14197#>3<#14197#> <#14198#>(cons<#14198#> <#14199#>-1<#14199#> <#14200#>(cons<#14200#> <#14201#>1<#14201#> <#14202#>(cons<#14202#> <#14203#>2<#14203#> <#14204#>(cons<#14204#> <#14205#>6<#14205#> <#14206#>empty)))))<#14206#>
<#63007#><#14210#>n<#14210#><#63007#> must indeed be inserted into the rest of the list. More concretely,
  1. <#63008#><#14212#>(first<#14212#>\ <#14213#>alon)<#14213#><#63008#> is <#63009#><#14214#>-1<#14214#><#63009#>
  2. <#63010#><#14215#>(insert<#14215#>\ <#14216#>n<#14216#>\ <#14217#>(rest<#14217#>\ <#14218#>alon))<#14218#><#63010#> is <#63011#><#14219#>(cons<#14219#>\ <#14220#>1<#14220#>\ <#14221#>(cons<#14221#>\ <#14222#>2<#14222#>\ <#14223#>(cons<#14223#>\ <#14224#>3<#14224#>\ <#14225#>(cons<#14225#>\ <#14226#>6<#14226#>\ <#14227#>empty))))<#14227#><#63011#>.
By <#63012#><#14229#>cons<#14229#><#63012#>ing <#63013#><#14230#>-1<#14230#><#63013#> onto this last list, we get the desired answer. Here is how we generalize from these examples. The problem requires a further case distinction. If <#63014#><#14231#>(first<#14231#>\ <#14232#>alon)<#14232#><#63014#> is smaller than (or equal to) <#63015#><#14233#>n<#14233#><#63015#>, all the items in <#63016#><#14234#>alon<#14234#><#63016#> are smaller than <#63017#><#14235#>n<#14235#><#63017#>; after all, <#63018#><#14236#>alon<#14236#><#63018#> is already sorted. The result is <#63019#><#14237#>(cons<#14237#>\ <#14238#>n<#14238#>\ <#14239#>alon)<#14239#><#63019#> for this case. If, however, <#63020#><#14240#>(first<#14240#>\ <#14241#>alon)<#14241#><#63020#> is larger than <#63021#><#14242#>n<#14242#><#63021#>, then we have not yet found the proper place to insert <#63022#><#14243#>n<#14243#><#63022#> into <#63023#><#14244#>alon<#14244#><#63023#>. We do know that the first item of the result must be the <#63024#><#14245#>(first<#14245#>\ <#14246#>alon)<#14246#><#63024#> and that <#63025#><#14247#>n<#14247#><#63025#> must be inserted into <#63026#><#14248#>(rest<#14248#>\ <#14249#>alon)<#14249#><#63026#>. The final result in this case is
<#14254#>(cons<#14254#> <#14255#>(first<#14255#> <#14256#>alon)<#14256#> <#14257#>(insert<#14257#> <#14258#>n<#14258#> <#14259#>(rest<#14259#> <#14260#>alon)))<#14260#>
because this list contains <#63027#><#14264#>n<#14264#><#63027#> and all items of <#63028#><#14265#>alon<#14265#><#63028#> in sorted order---which is what we need. The translation of this discussion into Scheme requires the formulation of a conditional expression that distinguishes between the two possible cases:
<#14270#>(c<#14270#><#14271#>ond<#14271#>
  <#14272#>[<#14272#><#14273#>(;SPMlt;=<#14273#> <#14274#>(first<#14274#> <#14275#>alon)<#14275#> <#14276#>n)<#14276#> <#14277#>...]<#14277#> 
  <#14278#>[<#14278#><#14279#>(;SPMgt;<#14279#> <#14280#>(first<#14280#> <#14281#>alon)<#14281#> <#14282#>n)<#14282#> <#14283#>...]<#14283#><#14284#>)<#14284#> 
From here, we just need to put the proper answer expressions into the two <#63029#><#14288#>cond<#14288#><#63029#>-clauses. Figure~#figsort#14289> contains the complete definitions of <#63030#><#14290#>insert<#14290#><#63030#> and <#63031#><#14291#>sort<#14291#><#63031#>.
<#71022#>;; <#63032#><#14296#>sort<#14296#> <#14297#>:<#14297#> <#14298#>list-of-numbers<#14298#> <#14299#><#14299#><#14300#>-;SPMgt;<#14300#><#14301#><#14301#> <#14302#>list-of-numbers<#14302#><#63032#><#71022#>
<#14303#>;; to create a list of numbers with the same numbers as<#14303#> 
<#71023#>;; <#63033#><#14304#>alon<#14304#><#63033#> sorted in descending order<#71023#> 
<#14305#>(d<#14305#><#14306#>efine<#14306#> <#14307#>(sort<#14307#> <#14308#>alon)<#14308#> 
  <#14309#>(c<#14309#><#14310#>ond<#14310#> 
    <#14311#>[<#14311#><#14312#>(empty?<#14312#> <#14313#>alon)<#14313#> <#14314#>empty]<#14314#> 
    <#14315#>[<#14315#><#14316#>(cons?<#14316#> <#14317#>alon)<#14317#> <#14318#>(insert<#14318#> <#14319#>(first<#14319#> <#14320#>alon)<#14320#> <#14321#>(sort<#14321#> <#14322#>(rest<#14322#> <#14323#>alon)))]<#14323#><#14324#>))<#14324#> 
<#71024#>;; <#63034#><#14325#>insert<#14325#> <#14326#>:<#14326#> <#14327#>number<#14327#> <#14328#>list-of-numbers<#14328#> <#14329#>(sorted)<#14329#> <#14330#><#14330#><#14331#>-;SPMgt;<#14331#><#14332#><#14332#> <#14333#>list-of-numbers<#14333#><#63034#><#71024#> 
<#71025#>;; to create a list of numbers from <#63035#><#14334#>n<#14334#><#63035#> and the numbers on<#71025#> 
<#71026#>;; <#63036#><#14335#>alon<#14335#><#63036#> that is sorted in descending order; <#63037#><#14336#>alon<#14336#><#63037#> is sorted<#71026#> 
<#14337#>(d<#14337#><#14338#>efine<#14338#> <#14339#>(insert<#14339#> <#14340#>n<#14340#> <#14341#>alon)<#14341#> 
  <#14342#>(c<#14342#><#14343#>ond<#14343#> 
    <#14344#>[<#14344#><#14345#>(empty?<#14345#> <#14346#>alon)<#14346#> <#14347#>(cons<#14347#> <#14348#>n<#14348#> <#14349#>empty)]<#14349#> 
    <#14350#>[<#14350#><#14351#>else<#14351#> <#14352#>(c<#14352#><#14353#>ond<#14353#> 
            <#14354#>[<#14354#><#14355#>(;SPMlt;=<#14355#> <#14356#>(first<#14356#> <#14357#>alon)<#14357#> <#14358#>n)<#14358#> <#14359#>(cons<#14359#> <#14360#>n<#14360#> <#14361#>alon)]<#14361#> 
            <#14362#>[<#14362#><#14363#>(;SPMgt;<#14363#> <#14364#>(first<#14364#> <#14365#>alon)<#14365#> <#14366#>n)<#14366#> <#14367#>(cons<#14367#> <#14368#>(first<#14368#> <#14369#>alon)<#14369#> <#14370#>(insert<#14370#> <#14371#>n<#14371#> <#14372#>(rest<#14372#> <#14373#>alon)))]<#14373#><#14374#>)]<#14374#><#14375#>))<#14375#> 
<#14379#>Figure: Sorting lists of numbers<#14379#>

<#14383#>Exercise 12.2.1<#14383#> Develop a program that sorts lists of mail messages by date. Mail structures are defined as follows:
<#14389#>(define-struct<#14389#> <#14390#>mail<#14390#> <#14391#>(from<#14391#> <#14392#>date<#14392#> <#14393#>message))<#14393#>
A <#63038#><#14398#>mail message<#14398#><#63038#> is a structure:

<#71027#><#63039#><#14399#>(make-structure<#14399#>\ <#14400#>name<#14400#>\ <#14401#>n<#14401#>\ <#14402#>s)<#14402#><#63039#><#71027#> where <#63040#><#14403#>name<#14403#><#63040#> is a string, <#63041#><#14404#>n<#14404#><#63041#> is a number, and <#63042#><#14405#>s<#14405#><#63042#> is a string.

Also develop a program that sorts lists of mail messages by name. To compare two strings alphabetically, use the <#63043#><#14407#>string;SPMlt;?<#14407#><#63043#> primitive. external Solution<#63044#><#63044#> <#14413#>Exercise 12.2.2<#14413#> Here is the function <#63045#><#14415#>search<#14415#><#63045#>:
<#71028#>;; <#63046#><#14420#>search<#14420#> <#14421#>:<#14421#> <#14422#>number<#14422#> <#14423#>list-of-numbers<#14423#> <#14424#><#14424#><#14425#>-;SPMgt;<#14425#><#14426#><#14426#> <#14427#>boolean<#14427#><#63046#><#71028#>
<#14428#>(d<#14428#><#14429#>efine<#14429#> <#14430#>(search<#14430#> <#14431#>n<#14431#> <#14432#>alon)<#14432#> 
  <#14433#>(c<#14433#><#14434#>ond<#14434#> 
    <#14435#>[<#14435#><#14436#>(empty?<#14436#> <#14437#>alon)<#14437#> <#14438#>false]<#14438#> 
    <#14439#>[<#14439#><#14440#>else<#14440#> <#14441#>(or<#14441#> <#14442#>(=<#14442#> <#14443#>(first<#14443#> <#14444#>alon)<#14444#> <#14445#>n)<#14445#> <#14446#>(search<#14446#> <#14447#>n<#14447#> <#14448#>(rest<#14448#> <#14449#>alon)))]<#14449#><#14450#>))<#14450#> 
It determines whether some number occurs in a list of numbers. The function may have to traverse the entire list to find out that the number of interest isn't contained in the list. Develop the function <#63047#><#14454#>search-sorted<#14454#><#63047#>, which determines whether a number occurs in a sorted list of numbers. The function must take advantage of the fact that the list is sorted.~ external Solution<#63048#><#63048#>