Each number specifies the distance between two dots. What we need is the
following picture, where each dot is annotated with the distance to the
left-most dot:
Instead of doubling as we go from <#39708#>100<#39708#> to <#39709#>200<#39709#> items, the time
quadruples. This is also the approximate relationship for going from <#39710#>200<#39710#>
to <#39711#>400<#39711#>, <#39712#>300<#39712#> to <#39713#>600<#39713#>, and so on.
<#71593#>;; <#67349#><#39600#>relative-2-absolute<#39600#> <#39601#>:<#39601#> <#39602#>(listof<#39602#> <#39603#>number)<#39603#> <#39604#><#39604#><#39605#>-;SPMgt;<#39605#><#39606#><#39606#> <#39607#>(listof<#39607#> <#39608#>number)<#39608#><#67349#><#71593#>
<#39609#>;; to convert a list of relative distances to a list of absolute distances<#39609#>
<#39610#>;; the first item on the list represents the distance to the origin<#39610#>
<#39611#>(d<#39611#><#39612#>efine<#39612#> <#39613#>(relative-2-absolute<#39613#> <#39614#>alon)<#39614#>
<#39615#>(c<#39615#><#39616#>ond<#39616#>
<#39617#>[<#39617#><#39618#>(empty?<#39618#> <#39619#>alon)<#39619#> <#39620#>empty]<#39620#>
<#39621#>[<#39621#><#39622#>else<#39622#> <#39623#>(cons<#39623#> <#39624#>(first<#39624#> <#39625#>alon)<#39625#>
<#39626#>(add-to-each<#39626#> <#39627#>(first<#39627#> <#39628#>alon)<#39628#> <#39629#>(relative-2-absolute<#39629#> <#39630#>(rest<#39630#> <#39631#>alon))))]<#39631#><#39632#>))<#39632#>
<#71594#>;; <#67350#><#39633#>add-to-each<#39633#> <#39634#>:<#39634#> <#39635#>number<#39635#> <#39636#>(listof<#39636#> <#39637#>number)<#39637#> <#39638#><#39638#><#39639#>-;SPMgt;<#39639#><#39640#><#39640#> <#39641#>(listof<#39641#> <#39642#>number)<#39642#><#67350#><#71594#>
<#71595#>;; to add <#67351#><#39643#>n<#39643#><#67351#> to each number on <#67352#><#39644#>alon<#39644#><#67352#><#71595#>
<#39645#>(d<#39645#><#39646#>efine<#39646#> <#39647#>(add-to-each<#39647#> <#39648#>n<#39648#> <#39649#>alon)<#39649#>
<#39650#>(c<#39650#><#39651#>ond<#39651#>
<#39652#>[<#39652#><#39653#>(empty?<#39653#> <#39654#>alon)<#39654#> <#39655#>empty]<#39655#>
<#39656#>[<#39656#><#39657#>else<#39657#> <#39658#>(cons<#39658#> <#39659#>(+<#39659#> <#39660#>(first<#39660#> <#39661#>alon)<#39661#> <#39662#>n)<#39662#> <#39663#>(add-to-each<#39663#> <#39664#>n<#39664#> <#39665#>(rest<#39665#> <#39666#>alon)))]<#39666#><#39667#>))<#39667#>
<#39671#>Figure: Converting relative distances to absolute distances<#39671#>
Developing a program that performs this calculation is at this point an
exercise in structural function design. Figure~#figrelabsdist#39673><#39689#>(define<#39689#> <#39690#>x<#39690#> <#39691#>(relative-2-absolute<#39691#> <#39692#>(list<#39692#> <#39693#>0<#39693#> <#39694#>...<#39694#> <#39695#>N)))<#39695#>
As we increase <#67358#><#39699#>N<#39699#><#67358#>, the time needed grows even
faster:
<#39716#>Exercise 30.1.1<#39716#>
<#39734#>(relative-2-absolute<#39734#> <#39735#>(list<#39735#> <#39736#>0<#39736#> <#39737#>...<#39737#> <#39738#>N))<#39738#>
by hand. Start by replacing <#67365#><#39742#>N<#39742#><#67365#> with 1, 2, and 3. How many natural
recursions of <#67366#><#39743#>relative-2-absolute<#39743#><#67366#> and <#67367#><#39744#>add-to-each<#39744#><#67367#> are
required each time?~ Solution<#67368#><#67368#>
Considering the simplicity of the problem, the amount of ``work'' that the
two functions perform is surprising. If we were to convert the same list by
hand, we would tally up the total distance and just add it to the relative
distances as we take another step along the line.
Let's attempt to design a second version of the function that is closer to
our hand method. The new function is still a list-processing function, so we
start from the appropriate template:
<#39756#>(d<#39756#><#39757#>efine<#39757#> <#39758#>(rel-2-abs<#39758#> <#39759#>alon)<#39759#>
<#39760#>(c<#39760#><#39761#>ond<#39761#>
<#39762#>[<#39762#><#39763#>(empty?<#39763#> <#39764#>alon)<#39764#> <#39765#>...]<#39765#>
<#39766#>[<#39766#><#39767#>else<#39767#> <#39768#>...<#39768#> <#39769#>(first<#39769#> <#39770#>alon)<#39770#> <#39771#>...<#39771#> <#39772#>(rel-2-abs<#39772#> <#39773#>(rest<#39773#> <#39774#>alon))<#39774#> <#39775#>...]<#39775#><#39776#>))<#39776#>
Now imagine an ``evaluation'' of <#67369#><#39780#>(rel-2-abs<#39780#>\ <#39781#>(list<#39781#>\ <#39782#>3<#39782#>\ <#39783#>2<#39783#>\ <#39784#>7))<#39784#><#67369#>:
<#39789#>(rel-2-abs<#39789#> <#39790#>(list<#39790#> <#39791#>3<#39791#> <#39792#>2<#39792#> <#39793#>7))<#39793#>
<#39794#>=<#39794#> <#39795#>(c<#39795#><#39796#>ons<#39796#> <#39797#>...<#39797#> <#39798#>3<#39798#> <#39799#>...<#39799#>
<#39800#>(convert<#39800#> <#39801#>(list<#39801#> <#39802#>2<#39802#> <#39803#>7)))<#39803#>
<#39804#>=<#39804#> <#39805#>(c<#39805#><#39806#>ons<#39806#> <#39807#>...<#39807#> <#39808#>3<#39808#> <#39809#>...<#39809#>
<#39810#>(c<#39810#><#39811#>ons<#39811#> <#39812#>...<#39812#> <#39813#>2<#39813#> <#39814#>...<#39814#>
<#39815#>(convert<#39815#> <#39816#>(list<#39816#> <#39817#>7))))<#39817#>
<#39818#>=<#39818#> <#39819#>(c<#39819#><#39820#>ons<#39820#> <#39821#>...<#39821#> <#39822#>3<#39822#> <#39823#>...<#39823#>
<#39824#>(c<#39824#><#39825#>ons<#39825#> <#39826#>...<#39826#> <#39827#>2<#39827#> <#39828#>...<#39828#>
<#39829#>(c<#39829#><#39830#>ons<#39830#> <#39831#>...<#39831#> <#39832#>7<#39832#> <#39833#>...<#39833#>
<#39834#>(convert<#39834#> <#39835#>empty))))<#39835#>
The first item of the result list should obviously be <#67370#><#39839#>3<#39839#><#67370#>, and it is
easy to construct this list. But, the second one should be <#67371#><#39840#>(+<#39840#>\ <#39841#>3<#39841#><#39842#> <#39842#><#39843#>2)<#39843#><#67371#>, yet the second instance of <#67372#><#39844#>rel-2-abs<#39844#><#67372#> has no way of
``knowing'' that the first item of the <#39845#>original<#39845#> list is
<#67373#><#39846#>3<#39846#><#67373#>. The ``knowledge'' is lost.
Put differently, the problem is that recursive functions are independent of
their context. A function processes the list <#67374#><#39847#>L<#39847#><#67374#> in <#67375#><#39848#>(cons<#39848#>\ <#39849#>N<#39849#><#39850#> <#39850#><#39851#>L)<#39851#><#67375#> in the exact same manner as <#67376#><#39852#>L<#39852#><#67376#> in <#67377#><#39853#>(cons<#39853#>\ <#39854#>K<#39854#>\ <#39855#>L)<#39855#><#67377#>. Indeed,
it would also process <#67378#><#39856#>L<#39856#><#67378#> in that manner if it were given <#67379#><#39857#>L<#39857#><#67379#>
by itself. While this property makes structurally recursive functions easy
to design, it also means that solutions are, on occasion, more complicated
than necessary, and this complication may affect the performance of the
function.
To make up for the loss of ``knowledge'', we equip the function with an
additional parameter: <#67380#><#39858#>accu-dist<#39858#><#67380#>. The new parameter represents
the accumulated distance, which is the tally that we keep when we convert a
list of relative distances to a list of absolute distances. Its initial
value must be <#67381#><#39859#>0<#39859#><#67381#>. As the function processes the numbers on the list,
it must add them to the tally.
Here is the revised definition:
<#39864#>(d<#39864#><#39865#>efine<#39865#> <#39866#>(rel-2-abs<#39866#> <#39867#>alon<#39867#> <#39868#>accu-dist)<#39868#>
<#39869#>(c<#39869#><#39870#>ond<#39870#>
<#39871#>[<#39871#><#39872#>(empty?<#39872#> <#39873#>alon)<#39873#> <#39874#>empty]<#39874#>
<#39875#>[<#39875#><#39876#>else<#39876#> <#39877#>(cons<#39877#> <#39878#>(+<#39878#> <#39879#>(first<#39879#> <#39880#>alon)<#39880#> <#39881#>accu-dist)<#39881#>
<#39882#>(rel-2-abs<#39882#> <#39883#>(rest<#39883#> <#39884#>alon)<#39884#> <#39885#>(+<#39885#> <#39886#>(first<#39886#> <#39887#>alon)<#39887#> <#39888#>accu-dist)))]<#39888#><#39889#>))<#39889#>
The recursive application consumes the rest of the list and the new
absolute distance of the current point to the origin. Although this means
that two arguments are changing simultaneously, the change in the second
one strictly depends on the first argument. The function is still a plain
list-processing procedure.
Evaluating our running example with <#67382#><#39893#>rel-2-abs<#39893#><#67382#> shows how much the
use of an accumulator simplifies the conversion process:
<#39898#>=<#39898#> <#39899#>(rel-2-abs<#39899#> <#39900#>(list<#39900#> <#39901#>3<#39901#> <#39902#>2<#39902#> <#39903#>7)<#39903#> <#39904#>0)<#39904#>
<#39905#>=<#39905#> <#39906#>(cons<#39906#> <#39907#>3<#39907#> <#39908#>(rel-2-abs<#39908#> <#39909#>(list<#39909#> <#39910#>2<#39910#> <#39911#>7)<#39911#> <#39912#>3))<#39912#>
<#39913#>=<#39913#> <#39914#>(cons<#39914#> <#39915#>3<#39915#> <#39916#>(cons<#39916#> <#39917#>5<#39917#> <#39918#>(rel-2-abs<#39918#> <#39919#>(list<#39919#> <#39920#>7)<#39920#> <#39921#>5)))<#39921#>
<#39922#>=<#39922#> <#39923#>(cons<#39923#> <#39924#>3<#39924#> <#39925#>(cons<#39925#> <#39926#>5<#39926#> <#39927#>(cons<#39927#> <#39928#>12<#39928#> <#39929#>(rel-2-abs<#39929#> <#39930#>empty<#39930#> <#39931#>12))))<#39931#>
<#39932#>=<#39932#> <#39933#>(cons<#39933#> <#39934#>3<#39934#> <#39935#>(cons<#39935#> <#39936#>5<#39936#> <#39937#>(cons<#39937#> <#39938#>12<#39938#> <#39939#>empty)))<#39939#>
Each item in the list is processed once. When <#67383#><#39943#>rel-2-abs<#39943#><#67383#>
reaches the end of the argument list, the result is completely determined
and no further work is needed. In general, the function performs on the
order of <#39944#>N<#39944#> natural recursion steps for a list with <#39945#>N<#39945#>
items.
One minor problem with the new definition is that the function consumes two
arguments and is thus not equivalent to <#67384#><#39946#>relative-2-absolute<#39946#><#67384#>, a
function of one argument. Worse, someone might accidentally misuse
<#67385#><#39947#>rel-2-abs<#39947#><#67385#> by applying it to a list of numbers and a number that
isn't <#67386#><#39948#>0<#39948#><#67386#>. We can solve both problems with a function definition
that contains <#67387#><#39949#>rel-2-abs<#39949#><#67387#> in a <#67388#><#39950#>local<#39950#><#67388#> definition: see
figure~#figrelabshuman#39951><#71598#>;; <#67391#><#39958#>relative-2-absolute2<#39958#> <#39959#>:<#39959#> <#39960#>(listof<#39960#> <#39961#>number)<#39961#> <#39962#><#39962#><#39963#>-;SPMgt;<#39963#><#39964#><#39964#> <#39965#>(listof<#39965#> <#39966#>number)<#39966#><#67391#><#71598#>
<#39967#>;; to convert a list of relative distances to a list of absolute distances<#39967#>
<#39968#>;; the first item on the list represents the distance to the origin<#39968#>
<#39969#>(d<#39969#><#39970#>efine<#39970#> <#39971#>(relative-2-absolute2<#39971#> <#39972#>alon)<#39972#>
<#39973#>(l<#39973#><#39974#>ocal<#39974#> <#39975#>((d<#39975#><#39976#>efine<#39976#> <#39977#>(rel-2-abs<#39977#> <#39978#>alon<#39978#> <#39979#>accu-dist)<#39979#>
<#39980#>(c<#39980#><#39981#>ond<#39981#>
<#39982#>[<#39982#><#39983#>(empty?<#39983#> <#39984#>alon)<#39984#> <#39985#>empty]<#39985#>
<#39986#>[<#39986#><#39987#>else<#39987#> <#39988#>(cons<#39988#> <#39989#>(+<#39989#> <#39990#>(first<#39990#> <#39991#>alon)<#39991#> <#39992#>accu-dist)<#39992#>
<#39993#>(rel-2-abs<#39993#> <#39994#>(rest<#39994#> <#39995#>alon)<#39995#> <#39996#>(+<#39996#> <#39997#>(first<#39997#> <#39998#>alon)<#39998#> <#39999#>accu-dist)))]<#39999#><#40000#>)))<#40000#>
<#40001#>(rel-2-abs<#40001#> <#40002#>alon<#40002#> <#40003#>0)))<#40003#>
<#40007#>Figure: Converting relative distances with an accumulator<#40007#>