Designing Abstractions with Functions-as-Values

The combination of <#65619#><#29839#>local<#29839#>-expression<#65619#>s and functions-as-values simplifies our recipe for creating abstract functions. Consider our very first example in figure~#figcmpabovebelow#29840> again. If we replace the contents of the boxes with <#65620#><#29841#>rel-op<#29841#><#65620#>, we get a function that has a free variable. To avoid this, we can either add <#65621#><#29842#>rel-op<#29842#><#65621#> to the parameters or we can wrap the definition in a <#65622#><#29843#>local<#29843#><#65622#> and prefix it with a function that consumes <#65623#><#29844#>rel-op<#29844#><#65623#>:
<#29849#>(d<#29849#><#29850#>efine<#29850#> <#29851#>(filter2<#29851#> <#29852#>rel-op)<#29852#>
  <#29853#>(l<#29853#><#29854#>ocal<#29854#> <#29855#>((d<#29855#><#29856#>efine<#29856#> <#29857#>(abs-fun<#29857#> <#29858#>alon<#29858#> <#29859#>t)<#29859#> 
            <#29860#>(c<#29860#><#29861#>ond<#29861#> 
              <#29862#>[<#29862#><#29863#>(empty?<#29863#> <#29864#>alon)<#29864#> <#29865#>empty]<#29865#> 
              <#29866#>[<#29866#><#29867#>e<#29867#><#29868#>lse<#29868#> 
                <#29869#>(c<#29869#><#29870#>ond<#29870#> 
                  <#29871#>[<#29871#><#29872#>(<#29872#>#tex2html_wrap73330# <#29874#>(first<#29874#> <#29875#>alon)<#29875#> <#29876#>t)<#29876#> 
                   <#29877#>(c<#29877#><#29878#>ons<#29878#> <#29879#>(first<#29879#> <#29880#>alon)<#29880#> 
                     <#29881#>(abs-fun<#29881#> <#29882#>(rest<#29882#> <#29883#>alon)<#29883#> <#29884#>t))]<#29884#> 
                  <#29885#>[<#29885#><#29886#>el<#29886#><#29887#>se<#29887#> 
                     <#29888#>(abs-fun<#29888#> <#29889#>(rest<#29889#> <#29890#>alon)<#29890#> <#29891#>t)]<#29891#><#29892#>)]<#29892#><#29893#>)))<#29893#> 
    <#29894#>abs-fun))<#29894#> 
If we also make the <#65625#><#29898#>local<#29898#><#65625#>ly defined function the result of the function, we have defined an abstraction of the two original functions. Put differently, we follow the example of <#65626#><#29899#>add<#29899#><#65626#> in the preceding section. Like <#65627#><#29900#>add<#29900#><#65627#>, <#65628#><#29901#>filter2<#29901#><#65628#> consumes an argument, defines a function, and returns this function as a result. The result remembers the <#65629#><#29902#>rel-op<#29902#><#65629#> argument for good as the following evaluation shows:
  <#29907#>(filter2<#29907#> <#29908#>;SPMlt;)<#29908#>
<#29916#>=<#29916#> <#29917#>(l<#29917#><#29918#>ocal<#29918#> <#29919#>((d<#29919#><#29920#>efine<#29920#> <#29921#>(abs-fun<#29921#> <#29922#>alon<#29922#> <#29923#>t)<#29923#>
            <#29924#>(c<#29924#><#29925#>ond<#29925#> 
              <#29926#>[<#29926#><#29927#>(empty?<#29927#> <#29928#>alon)<#29928#> <#29929#>empty]<#29929#> 
              <#29930#>[<#29930#><#29931#>e<#29931#><#29932#>lse<#29932#> 
                <#29933#>(c<#29933#><#29934#>ond<#29934#> 
                  <#29935#>[<#29935#><#29936#>(;SPMlt;<#29936#> <#29937#>(first<#29937#> <#29938#>alon)<#29938#> <#29939#>t)<#29939#> 
                   <#29940#>(c<#29940#><#29941#>ons<#29941#> <#29942#>(first<#29942#> <#29943#>alon)<#29943#> 
                     <#29944#>(abs-fun<#29944#> <#29945#>(rest<#29945#> <#29946#>alon)<#29946#> <#29947#>t))]<#29947#> 
                  <#29948#>[<#29948#><#29949#>el<#29949#><#29950#>se<#29950#> 
                     <#29951#>(abs-fun<#29951#> <#29952#>(rest<#29952#> <#29953#>alon)<#29953#> <#29954#>t)]<#29954#><#29955#>)]<#29955#><#29956#>)))<#29956#> 
    <#29957#>abs-fun)<#29957#> 
<#29965#>=<#29965#> <#29966#>(<#29966#><#29967#>d<#29967#><#29968#>efine<#29968#> <#29969#>(below3<#29969#> <#29970#>alon<#29970#> <#29971#>t)<#29971#>
    <#29972#>(c<#29972#><#29973#>ond<#29973#> 
      <#29974#>[<#29974#><#29975#>(empty?<#29975#> <#29976#>alon)<#29976#> <#29977#>empty]<#29977#> 
      <#29978#>[<#29978#><#29979#>e<#29979#><#29980#>lse<#29980#> 
        <#29981#>(c<#29981#><#29982#>ond<#29982#> 
          <#29983#>[<#29983#><#29984#>(;SPMlt;<#29984#> <#29985#>(first<#29985#> <#29986#>alon)<#29986#> <#29987#>t)<#29987#> 
           <#29988#>(c<#29988#><#29989#>ons<#29989#> <#29990#>(first<#29990#> <#29991#>alon)<#29991#> 
             <#29992#>(below3<#29992#> <#29993#>(rest<#29993#> <#29994#>alon)<#29994#> <#29995#>t))]<#29995#> 
          <#29996#>[<#29996#><#29997#>e<#29997#><#29998#>lse<#29998#> 
            <#29999#>(below3<#29999#> <#30000#>(rest<#30000#> <#30001#>alon)<#30001#> <#30002#>t)]<#30002#><#30003#>)]<#30003#><#30004#>))<#30004#> 
   <#30005#>below3<#30005#> 
Remember that as we lift a <#65630#><#30009#>local<#30009#><#65630#> definition to the top-level definitions, we also rename the function in case the same <#65631#><#30010#>local<#30010#><#65631#> is evaluated again. Here we choose the name <#65632#><#30011#>below3<#30011#><#65632#> to indicate what the function does. And indeed, a comparison between <#65633#><#30012#>below<#30012#><#65633#> and <#65634#><#30013#>below3<#30013#><#65634#> reveals that the only difference is the name of the function. From the calculation, it follows that we can give the result of <#65635#><#30014#>(filter2<#30014#>\ <#30015#>;SPMlt;)<#30015#><#65635#> a name and use it as if it were <#65636#><#30016#>below<#30016#><#65636#>. More succinctly,
<#30021#>(define<#30021#> <#30022#>below2<#30022#> <#30023#>(filter2<#30023#> <#30024#>;SPMlt;))<#30024#>
is equivalent to
<#30032#>(def<#30032#><#30033#>ine<#30033#> <#30034#>(below3<#30034#> <#30035#>alon<#30035#> <#30036#>t)<#30036#>
    <#30037#>(c<#30037#><#30038#>ond<#30038#> 
      <#30039#>[<#30039#><#30040#>(empty?<#30040#> <#30041#>alon)<#30041#> <#30042#>empty]<#30042#> 
      <#30043#>[<#30043#><#30044#>e<#30044#><#30045#>lse<#30045#> 
        <#30046#>(c<#30046#><#30047#>ond<#30047#> 
          <#30048#>[<#30048#><#30049#>(;SPMlt;<#30049#> <#30050#>(first<#30050#> <#30051#>alon)<#30051#> <#30052#>t)<#30052#> 
           <#30053#>(c<#30053#><#30054#>ons<#30054#> <#30055#>(first<#30055#> <#30056#>alon)<#30056#> 
             <#30057#>(below3<#30057#> <#30058#>(rest<#30058#> <#30059#>alon)<#30059#> <#30060#>t))]<#30060#> 
          <#30061#>[<#30061#><#30062#>e<#30062#><#30063#>lse<#30063#> 
            <#30064#>(below3<#30064#> <#30065#>(rest<#30065#> <#30066#>alon)<#30066#> <#30067#>t)]<#30067#><#30068#>)]<#30068#><#30069#>))<#30069#> 
<#30070#>(define<#30070#> <#30071#>below2<#30071#> <#30072#>below3)<#30072#> 
which means <#65637#><#30076#>below2<#30076#><#65637#> is just another name for <#65638#><#30077#>below3<#30077#><#65638#> and which directly proves that our abstract function correctly implements <#65639#><#30078#>below<#30078#><#65639#>. The example suggests a variant of the abstraction recipe from section~#secdesignabstract#30079>:
The comparison:
The new recipe still requires us to compare and to mark the differences.
The abstraction:
The new step concerns the way we define the abstract function. We place one of the functions into a <#65640#><#30081#>local<#30081#>-expression<#65640#> and use the name of the function as the body of the <#65641#><#30082#>local<#30082#><#65641#>:
<#30087#>(l<#30087#><#30088#>ocal<#30088#> <#30089#>((d<#30089#><#30090#>efine<#30090#> <#30091#>(concrete-fun<#30091#> <#30092#>x<#30092#> <#30093#>y<#30093#> <#30094#>z)<#30094#>
          <#30095#>...<#30095#> #tex2html_wrap73332# <#30097#>...<#30097#> #tex2html_wrap73334# <#30099#>...))<#30099#> 
  <#30100#>concrete-fun)<#30100#> 
From that, we can create the abstract function by listing the names in the boxes as parameters:
<#30108#>(d<#30108#><#30109#>efine<#30109#> <#30110#>(abs-fun<#30110#> <#30111#>op1<#30111#> <#30112#>op2)<#30112#>
  <#30113#>(l<#30113#><#30114#>ocal<#30114#> <#30115#>((d<#30115#><#30116#>efine<#30116#> <#30117#>(concrete-fun<#30117#> <#30118#>x<#30118#> <#30119#>y<#30119#> <#30120#>z)<#30120#> 
            <#30121#>...<#30121#> #tex2html_wrap73336# <#30123#>...<#30123#> #tex2html_wrap73338# <#30125#>...))<#30125#> 
    <#30126#>concrete-fun))<#30126#> 
If <#65646#><#30130#>op1<#30130#><#65646#> or <#65647#><#30131#>op2<#30131#><#65647#> is a special symbol, say <#65648#><#30132#>;SPMlt;<#30132#><#65648#>, we rename it into something that is more meaningful in the new context.
The test:
To test the abstract function, we define the concrete functions again, as before. Consider the example of <#65649#><#30133#>below<#30133#><#65649#> and <#65650#><#30134#>above<#30134#><#65650#>. Obtaining <#65651#><#30135#>below<#30135#><#65651#> and <#65652#><#30136#>above<#30136#><#65652#> as instances of <#65653#><#30137#>filter2<#30137#><#65653#> is now straightforward:
<#30142#>(define<#30142#> <#30143#>below2<#30143#> <#30144#>(filter2<#30144#> <#30145#>;SPMlt;))<#30145#>
<#30146#>(define<#30146#> <#30147#>above2<#30147#> <#30148#>(filter2<#30148#> <#30149#>;SPMgt;))<#30149#> 
We simply apply <#65654#><#30153#>filter2<#30153#><#65654#> to the contents of the box in the respective concrete function and that application produces the old function.
The contract:
The contract of an abstract function contains two arrows. After all, the function produces a function, and to describe this relationship the type to the right of the first arrow must contain another arrow. Here is the contract for <#65655#><#30154#>filter2<#30154#><#65655#>:
<#71379#>;; <#65656#><#30159#>filter2<#30159#> <#30160#>:<#30160#> <#30161#>(X<#30161#> <#30162#>Y<#30162#> <#30163#><#30163#><#30164#>-;SPMgt;<#30164#><#30165#><#30165#> <#30166#>boolean)<#30166#> <#30167#><#30167#><#30168#>-;SPMgt;<#30168#><#30169#><#30169#> <#30170#>(Y<#30170#> <#30171#>(listof<#30171#> <#30172#>X)<#30172#> <#30173#><#30173#><#30174#>-;SPMgt;<#30174#><#30175#><#30175#> <#30176#>(listof<#30176#> <#30177#>X))<#30177#><#65656#><#71379#>
It consumes a comparison function and produces a concrete filter-style function. The generalization of the contract works as before.
Given our experience with the first design recipe, the second one is only a question of practice.
<#30184#>Exercise 22.2.1<#30184#> Define an abstraction of the functions <#65657#><#30186#>convertCF<#30186#><#65657#> and <#65658#><#30187#>names<#30187#><#65658#> from section~#secpostabs#30188> using the new recipe for abstraction.~ external Solution<#65659#><#65659#> <#30194#>Exercise 22.2.2<#30194#> Define an abstract version of <#65660#><#30196#>sort<#30196#><#65660#> (see exercise~#exabssort#30197>) using the new recipe for abstraction.~ external Solution<#65661#><#65661#> <#30203#>Exercise 22.2.3<#30203#> Define <#65662#><#30205#>fold<#30205#><#65662#> using the new recipe for abstraction. Recall that <#65663#><#30206#>fold<#30206#><#65663#> abstracts the following pair of functions:
<#71380#>;; <#65664#><#30211#>sum<#30211#> <#30212#>:<#30212#> <#30213#>(listof<#30213#> <#30214#>number)<#30214#> <#30215#><#30215#><#30216#>-;SPMgt;<#30216#><#30217#><#30217#> <#30218#>number<#30218#><#65664#><#71380#>
<#71381#>;; to compute the sum of <#65665#><#30219#>alon<#30219#><#65665#><#71381#> 
<#30220#>(d<#30220#><#30221#>efine<#30221#> <#30222#>(sum<#30222#> <#30223#>alon)<#30223#> 
  <#30224#>(c<#30224#><#30225#>ond<#30225#> 
    <#30226#>[<#30226#><#30227#>(empty?<#30227#> <#30228#>alon)<#30228#> <#30229#>0]<#30229#> 
    <#30230#>[<#30230#><#30231#>else<#30231#> <#30232#>(+<#30232#> <#30233#>(first<#30233#> <#30234#>alon)<#30234#> 
             <#30235#>(sum<#30235#> <#30236#>(rest<#30236#> <#30237#>alon)))]<#30237#><#30238#>))<#30238#> 
<#71382#>;; <#65666#><#30244#>product<#30244#> <#30245#>:<#30245#> <#30246#>(listof<#30246#> <#30247#>number)<#30247#> <#30248#><#30248#><#30249#>-;SPMgt;<#30249#><#30250#><#30250#> <#30251#>number<#30251#><#65666#><#71382#>
<#71383#>;; to compute the product of <#65667#><#30252#>alon<#30252#><#65667#><#71383#> 
<#30253#>(d<#30253#><#30254#>efine<#30254#> <#30255#>(product<#30255#> <#30256#>alon)<#30256#> 
  <#30257#>(c<#30257#><#30258#>ond<#30258#> 
    <#30259#>[<#30259#><#30260#>(empty?<#30260#> <#30261#>alon)<#30261#> <#30262#>1]<#30262#> 
    <#30263#>[<#30263#><#30264#>else<#30264#> <#30265#>(*<#30265#> <#30266#>(first<#30266#> <#30267#>alon)<#30267#> 
             <#30268#>(product<#30268#> <#30269#>(rest<#30269#> <#30270#>alon)))]<#30270#><#30271#>))<#30271#> 
external Solution<#65668#><#65668#>