Generalizing Problems, Generalizing Functions

Consider the problem of drawing a <#14462#>polygon<#14462#>, that is, a geometric shape with an arbitrary number of corners. A natural representation for a polygon is a list of <#63049#><#14464#>posn<#14464#><#63049#> structures:
A <#63050#><#14466#>list of posns<#14466#><#63050#> (<#63051#><#14467#>list-of-posns<#14467#><#63051#>) is either
  1. the empty list, <#63052#><#14469#>empty<#14469#><#63052#>, or
  2. <#63053#><#14470#>(cons<#14470#>\ <#14471#>p<#14471#>\ <#14472#>lop)<#14472#><#63053#> where <#63054#><#14473#>p<#14473#><#63054#> is a <#63055#><#14474#>posn<#14474#><#63055#> structure and <#63056#><#14475#>lop<#14475#><#63056#> is a list of posns.
Each <#63057#><#14478#>posn<#14478#><#63057#> represents one corner of the polygon. For example,
<#14483#>(c<#14483#><#14484#>ons<#14484#> <#14485#>(make-posn<#14485#> <#14486#>10<#14486#> <#14487#>10)<#14487#>
  <#14488#>(c<#14488#><#14489#>ons<#14489#> <#14490#>(make-posn<#14490#> <#14491#>60<#14491#> <#14492#>60)<#14492#> 
    <#14493#>(c<#14493#><#14494#>ons<#14494#> <#14495#>(make-posn<#14495#> <#14496#>10<#14496#> <#14497#>60)<#14497#> 
      <#14498#>empty)))<#14498#> 
represents a triangle. The question is what <#63058#><#14502#>empty<#14502#><#63058#> means as a polygon. The answer is that <#63059#><#14503#>empty<#14503#><#63059#> does not represent a polygon and therefore shouldn't be included in the class of polygon representations. A polygon should always have at least one corner, and the lists that represent polygons should always contain at least one <#63060#><#14504#>posn<#14504#><#63060#>. This suggest the following data definition:
A <#63061#><#14506#>polygon<#14506#><#63061#> is either
  1. <#63062#><#14508#>(cons<#14508#>\ <#14509#>p<#14509#>\ <#14510#>empty)<#14510#><#63062#> where <#63063#><#14511#>p<#14511#><#63063#> is a <#63064#><#14512#>posn<#14512#><#63064#>, or
  2. <#63065#><#14513#>(cons<#14513#>\ <#14514#>p<#14514#>\ <#14515#>lop)<#14515#><#63065#> where <#63066#><#14516#>p<#14516#><#63066#> is a <#63067#><#14517#>posn<#14517#><#63067#> structure and <#63068#><#14518#>lop<#14518#><#63068#> is a polygon.
In short, a discussion of how the chosen set of data (lists of <#63069#><#14521#>posn<#14521#><#63069#>s) represents the intended information (geometric polygons) revealed that our choice was inadequate. Revising the data definition brought us closer to our intentions and makes it easier to design the program. Because our drawing primitives always produce <#63070#><#14522#>true<#14522#><#63070#> (if anything), it is natural to suggest the following contract and purpose statement:
<#71029#>;; <#63071#><#14527#>draw-polygon<#14527#> <#14528#>:<#14528#> <#14529#>polygon<#14529#> <#14530#><#14530#><#14531#>-;SPMgt;<#14531#><#14532#><#14532#> <#14533#>true<#14533#><#63071#><#71029#>
<#71030#>;; to draw the polygon specified by <#63072#><#14534#>a-poly<#14534#><#63072#> <#71030#> 
<#14535#>(define<#14535#> <#14536#>(draw-polygon<#14536#> <#14537#>a-poly)<#14537#> <#14538#>...)<#14538#> 
In other words, the function draws the lines between the corners and, if all primitive drawing steps work out, it produces <#63073#><#14542#>true<#14542#><#63073#>. For example, the above list of <#63074#><#14543#>posn<#14543#><#63074#>s should produce a triangle. Although the data definition is not just a variant on our well-worn list theme, the template is close to that of a list-processing function:
 
<#71031#>;; <#63075#><#14548#>draw-polygon<#14548#> <#14549#>:<#14549#> <#14550#>polygon<#14550#> <#14551#><#14551#><#14552#>-;SPMgt;<#14552#><#14553#><#14553#> <#14554#>true<#14554#><#63075#><#71031#> 
<#71032#>;; to draw the polygon specified by <#63076#><#14555#>a-poly<#14555#><#63076#> <#71032#> 
<#14556#>(d<#14556#><#14557#>efine<#14557#> <#14558#>(draw-polygon<#14558#> <#14559#>a-poly)<#14559#> 
  <#14560#>(c<#14560#><#14561#>ond<#14561#> 
    <#14562#>[<#14562#><#14563#>(empty?<#14563#> <#14564#>(rest<#14564#> <#14565#>a-poly))<#14565#> <#14566#>...<#14566#> <#14567#>(first<#14567#> <#14568#>a-poly)<#14568#> <#14569#>...]<#14569#> 
    <#14570#>[<#14570#><#14571#>els<#14571#><#14572#>e<#14572#> <#14573#>...<#14573#> <#14574#>(first<#14574#> <#14575#>a-poly)<#14575#> <#14576#>...<#14576#> 
        <#14577#>...<#14577#> <#14578#>(second<#14578#> <#14579#>a-poly)<#14579#> <#14580#>...<#14580#> 
        <#14581#>...<#14581#> <#14582#>(draw-polygon<#14582#> <#14583#>(rest<#14583#> <#14584#>a-poly))<#14584#> <#14585#>...]<#14585#><#14586#>))<#14586#> 
Given that both clauses in the data definition use <#63077#><#14590#>cons<#14590#><#63077#>, the first condition must inspect the rest of the list, which is <#63078#><#14591#>empty<#14591#><#63078#> for the first case and non-empty for the second one. Furthermore, in the first clause, we can add <#63079#><#14592#>(first<#14592#>\ <#14593#>a-poly)<#14593#><#63079#>; and in the second case, we not only have the first item on the list but the second one, too. After all, polygons generated according to the second clause consist of at least two <#63080#><#14594#>posn<#14594#><#63080#>s. Now we can replace the ``...'' in the template to obtain a complete function definition. For the first clause, the answer must be <#63081#><#14595#>true<#14595#><#63081#>, because we don't have two <#63082#><#14596#>posn<#14596#><#63082#>s that we could connect to form a line. For the second clause, we have two <#63083#><#14597#>posn<#14597#><#63083#>s, we can draw a line between them, and we know that <#63084#><#14598#>(draw-polygon<#14598#><#14599#> <#14599#><#14600#>(rest<#14600#>\ <#14601#>a-poly))<#14601#><#63084#> draws all the remaining lines. Put differently, we can write
<#14606#>(draw-solid-line<#14606#> <#14607#>(first<#14607#> <#14608#>a-poly)<#14608#> <#14609#>(second<#14609#> <#14610#>a-poly))<#14610#>
in the second clause because we know that <#63085#><#14614#>a-poly<#14614#><#63085#> has a second item. Both <#63086#><#14615#>(draw-solid-line<#14615#>\ <#14616#>...)<#14616#><#63086#> and <#63087#><#14617#>(draw-poly<#14617#>\ <#14618#>...)<#14618#><#63087#> produce <#63088#><#14619#>true<#14619#><#63088#> if everything goes fine. By combining the two expressions with <#63089#><#14620#>and<#14620#><#63089#>, <#63090#><#14621#>draw-poly<#14621#><#63090#> draws all lines. Here is the complete function definition:
 
<#14626#>(d<#14626#><#14627#>efine<#14627#> <#14628#>(draw-polygon<#14628#> <#14629#>a-poly)<#14629#> 
  <#14630#>(c<#14630#><#14631#>ond<#14631#> 
    <#14632#>[<#14632#><#14633#>(empty?<#14633#> <#14634#>(rest<#14634#> <#14635#>a-poly))<#14635#> <#14636#>true]<#14636#> 
    <#14637#>[<#14637#><#14638#>else<#14638#> <#14639#>(and<#14639#> <#14640#>(draw-solid-line<#14640#> <#14641#>(first<#14641#> <#14642#>a-poly)<#14642#> <#14643#>(second<#14643#> <#14644#>a-poly))<#14644#> 
               <#14645#>(draw-polygon<#14645#> <#14646#>(rest<#14646#> <#14647#>a-poly)))]<#14647#><#14648#>))<#14648#> 
Unfortunately, testing it with our triangle example immediately reveals a flaw. Instead of drawing a polygon with three sides, the function draws only an open curve, connecting all the corners but not closing the curve:

#picture14653#

Mathematically put, we have defined a more general function than the one we wanted. The function we defined should be called ``connect-the-dots'' and not <#63100#><#14668#>draw-polygon<#14668#><#63100#>. To get from the more general function to what we want, we need to figure out some way to connect the last dot to the first one. There are several different ways to accomplish this goal, but all of them mean that we define the main function in terms of the function we just defined or something like it. In other words, we define one auxiliary function in terms of a more general one. One way to define the new function is to add the first position of a polygon to the end and to have this new list drawn. A symmetric method is to pick the last one and add it to the front of the polygon. A third alternative is to modify the above version of <#63101#><#14669#>draw-polygon<#14669#><#63101#> so that it connects the last <#63102#><#14670#>posn<#14670#><#63102#> to the first one. Here we discuss the first alternative; the exercises cover the other two. To add the last item of <#63103#><#14671#>a-poly<#14671#><#63103#> at the beginning, we need something like

<#14676#>(cons<#14676#> <#14677#>(last<#14677#> <#14678#>a-poly)<#14678#> <#14679#>a-poly)<#14679#>
where <#63104#><#14683#>last<#14683#><#63104#> is some auxiliary function that extracts the last item from a non-empty list. Indeed, this expression is the definition of <#63105#><#14684#>draw-polygon<#14684#><#63105#> assuming we define <#63106#><#14685#>last<#14685#><#63106#>: see figure~#figdrawpoly#14686>. Formulating the wish list entry for <#63107#><#14687#>last<#14687#><#63107#> is straightforward:
<#71033#>;; <#63108#><#14692#>last<#14692#> <#14693#>:<#14693#> <#14694#>polygon<#14694#> <#14695#><#14695#><#14696#>-;SPMgt;<#14696#><#14697#><#14697#> <#14698#>posn<#14698#><#63108#><#71033#>
<#71034#>;; to extract the last <#63109#><#14699#>posn<#14699#><#63109#> on <#63110#><#14700#>a-poly<#14700#><#63110#><#71034#> 
<#14701#>(define<#14701#> <#14702#>(last<#14702#> <#14703#>a-poly)<#14703#> <#14704#>...)<#14704#> 
And, because <#63111#><#14708#>last<#14708#><#63111#> consumes a polygon, we can reuse the template from above:
 
<#14713#>(d<#14713#><#14714#>efine<#14714#> <#14715#>(last<#14715#> <#14716#>a-poly)<#14716#> 
  <#14717#>(c<#14717#><#14718#>ond<#14718#> 
    <#14719#>[<#14719#><#14720#>(empty?<#14720#> <#14721#>(rest<#14721#> <#14722#>a-poly))<#14722#> <#14723#>...<#14723#> <#14724#>(first<#14724#> <#14725#>a-poly)<#14725#> <#14726#>...]<#14726#> 
    <#14727#>[<#14727#><#14728#>els<#14728#><#14729#>e<#14729#> <#14730#>...<#14730#> <#14731#>(first<#14731#> <#14732#>a-poly)<#14732#> <#14733#>...<#14733#> 
        <#14734#>...<#14734#> <#14735#>(second<#14735#> <#14736#>a-poly)<#14736#> <#14737#>...<#14737#> 
        <#14738#>...<#14738#> <#14739#>(last<#14739#> <#14740#>(rest<#14740#> <#14741#>a-poly))<#14741#> <#14742#>...]<#14742#><#14743#>))<#14743#> 
Turning the template into a complete function is a short step. If the list is empty except for one item, this item is the desired result. If <#63112#><#14747#>(rest<#14747#>\ <#14748#>a-poly)<#14748#><#63112#> is not empty, <#63113#><#14749#>(last<#14749#>\ <#14750#>(rest<#14750#>\ <#14751#>a-poly))<#14751#><#63113#> determines the last item of <#63114#><#14752#>a-poly<#14752#><#63114#>. The complete definition of <#63115#><#14753#>last<#14753#><#63115#> is displayed at the bottom of figure~#figdrawpoly#14754>.
<#71035#>;; <#63116#><#14759#>draw-polygon<#14759#> <#14760#>:<#14760#> <#14761#>polygon<#14761#> <#14762#><#14762#><#14763#>-;SPMgt;<#14763#><#14764#><#14764#> <#14765#>true<#14765#><#63116#><#71035#>
<#14766#>;; to draw the polygon specified by a-poly <#14766#> 
<#14767#>(d<#14767#><#14768#>efine<#14768#> <#14769#>(draw-polygon<#14769#> <#14770#>a-poly)<#14770#> 
  <#14771#>(connect-dots<#14771#> <#14772#>(cons<#14772#> <#14773#>(last<#14773#> <#14774#>a-poly)<#14774#> <#14775#>a-poly)))<#14775#> 
<#71036#>;; <#63117#><#14776#>connect-dots<#14776#> <#14777#>:<#14777#> <#14778#>polygon<#14778#> <#14779#><#14779#><#14780#>-;SPMgt;<#14780#><#14781#><#14781#> <#14782#>true<#14782#><#63117#><#71036#> 
<#71037#>;; to draw connections between the dots of <#63118#><#14783#>a-poly<#14783#><#63118#><#71037#> 
<#14784#>(d<#14784#><#14785#>efine<#14785#> <#14786#>(connect-dots<#14786#> <#14787#>a-poly)<#14787#> 
  <#14788#>(c<#14788#><#14789#>ond<#14789#> 
    <#14790#>[<#14790#><#14791#>(empty?<#14791#> <#14792#>(rest<#14792#> <#14793#>a-poly))<#14793#> <#14794#>true]<#14794#> 
    <#14795#>[<#14795#><#14796#>else<#14796#> <#14797#>(and<#14797#> <#14798#>(draw-solid-line<#14798#> <#14799#>(first<#14799#> <#14800#>a-poly)<#14800#> <#14801#>(second<#14801#> <#14802#>a-poly)<#14802#> <#14803#>RED)<#14803#> 
               <#14804#>(connect-dots<#14804#> <#14805#>(rest<#14805#> <#14806#>a-poly)))]<#14806#><#14807#>))<#14807#> 
<#71038#>;; <#63119#><#14808#>last<#14808#> <#14809#>:<#14809#> <#14810#>polygon<#14810#> <#14811#><#14811#><#14812#>-;SPMgt;<#14812#><#14813#><#14813#> <#14814#>posn<#14814#><#63119#><#71038#> 
<#71039#>;; to extract the last <#63120#><#14815#>posn<#14815#><#63120#> on <#63121#><#14816#>a-poly<#14816#><#63121#><#71039#> 
<#14817#>(d<#14817#><#14818#>efine<#14818#> <#14819#>(last<#14819#> <#14820#>a-poly)<#14820#> 
  <#14821#>(c<#14821#><#14822#>ond<#14822#> 
    <#14823#>[<#14823#><#14824#>(empty?<#14824#> <#14825#>(rest<#14825#> <#14826#>a-poly))<#14826#> <#14827#>(first<#14827#> <#14828#>a-poly)]<#14828#> 
    <#14829#>[<#14829#><#14830#>else<#14830#> <#14831#>(last<#14831#> <#14832#>(rest<#14832#> <#14833#>a-poly))]<#14833#><#14834#>))<#14834#> 
<#14838#>Figure: Drawing a polygon<#14838#>
In summary, the development of <#63122#><#14840#>draw-polygon<#14840#><#63122#> naturally led us to consider a more general problem: connecting a list of dots. We solved the originally problem by defining a function that uses (a variant of) the more general function. As we will see again and again, generalizing the purpose of a function is often the best method to simplify the problem.
<#14843#>Exercise 12.3.1<#14843#> Modify <#63123#><#14845#>draw-polygon<#14845#><#63123#> so that it adds the first item of <#63124#><#14846#>a-poly<#14846#><#63124#> to its end. This requires a different auxiliary function: <#63125#><#14847#>add-at-end<#14847#><#63125#>.~ external Solution<#63126#><#63126#> <#14853#>Exercise 12.3.2<#14853#> Modify <#63127#><#14855#>connect-dots<#14855#><#63127#> so that it consumes an additional <#63128#><#14856#>posn<#14856#><#63128#> structure to which the last <#63129#><#14857#>posn<#14857#><#63129#> is connected. Then modify <#63130#><#14858#>draw-polygon<#14858#><#63130#> to use this new version of <#63131#><#14859#>connect-dots<#14859#><#63131#>.

<#14860#>Accumulator:<#14860#>:\ The new version of <#63132#><#14861#>connect-dots<#14861#><#63132#> is a simple instance of an accumulator-style function. In part~#partloops#14862> we will discuss an entire class of such problems.~ external Solution<#63133#><#63133#>