<#71599#><#67396#> <#71600#> <#67400#><#40059#>(cons<#40059#>\ <#40060#>S<#40060#>\ <#40061#>(cons<#40061#>\ <#40062#>T<#40062#>\ <#40063#>empty))<#40063#><#67400#> <#71600#> where <#67401#><#40064#>S<#40064#><#67401#>, <#67402#><#40065#>T<#40065#><#67402#> are symbols. <#71601#><#67405#><#40070#>(listof<#40070#>\ <#40071#>pair)<#40071#><#67405#>.<#71601#> <#40031#>(d<#40031#><#40032#>efine<#40032#> <#40033#>SimpleG<#40033#>
<#40034#>'<#40034#><#40035#>(<#40035#><#40036#>(A<#40036#> <#40037#>B)<#40037#>
<#40038#>(B<#40038#> <#40039#>C)<#40039#>
<#40040#>(C<#40040#> <#40041#>E)<#40041#>
<#40042#>(D<#40042#> <#40043#>E)<#40043#>
<#40044#>(E<#40044#> <#40045#>B)<#40045#>
<#40046#>(F<#40046#> <#40047#>F)))<#40047#>
<#67396#><#71599#>
<#40050#>Figure: A simple graph<#40050#>
The right part of figure~#figsimgraph#40052> A <#67397#><#40054#>node<#40054#><#67397#> is a symbol.
A <#67398#><#40057#>pair<#40057#><#67398#> is a list of two <#67399#><#40058#>node<#40058#><#67399#>s:
A <#67403#><#40068#>simple-graph<#40068#><#67403#> is a list of <#67404#><#40069#>pair<#40069#><#67404#>s:
They are straightforward translations of our informal
descriptions.
Finding a route in a graph is a problem of generative recursion. We have
data definitions, we have (informal) examples, and the header material is
standard:
<#71602#>;; <#67406#><#40077#>route-exists?<#40077#> <#40078#>:<#40078#> <#40079#>node<#40079#> <#40080#>node<#40080#> <#40081#>simple-graph<#40081#> <#40082#><#40082#><#40083#>-;SPMgt;<#40083#><#40084#><#40084#> <#40085#>boolean<#40085#><#67406#><#71602#>
<#71603#>;; to determine whether there is a route from <#67407#><#40086#>orig<#40086#><#67407#> to <#67408#><#40087#>dest<#40087#><#67408#> in <#67409#><#40088#>sg<#40088#><#67409#><#71603#>
<#40089#>(define<#40089#> <#40090#>(route-exists?<#40090#> <#40091#>orig<#40091#> <#40092#>dest<#40092#> <#40093#>sg)<#40093#> <#40094#>...)<#40094#>
What we need are answers to the four basic questions of the recipe for
generative recursion:
From here we just need to express these answers in Scheme, and we get an
algorithm. Figure~#figrouteexists1#40110><#71604#>;; <#67420#><#40115#>route-exists?<#40115#> <#40116#>:<#40116#> <#40117#>node<#40117#> <#40118#>node<#40118#> <#40119#>simple-graph<#40119#> <#40120#><#40120#><#40121#>-;SPMgt;<#40121#><#40122#><#40122#> <#40123#>boolean<#40123#><#67420#><#71604#>
<#71605#>;; to determine whether there is a route from <#67421#><#40124#>orig<#40124#><#67421#> to <#67422#><#40125#>dest<#40125#><#67422#> in <#67423#><#40126#>sg<#40126#><#67423#><#71605#>
<#40127#>(d<#40127#><#40128#>efine<#40128#> <#40129#>(route-exists?<#40129#> <#40130#>orig<#40130#> <#40131#>dest<#40131#> <#40132#>sg)<#40132#>
<#40133#>(c<#40133#><#40134#>ond<#40134#>
<#40135#>[<#40135#><#40136#>(symbol=?<#40136#> <#40137#>orig<#40137#> <#40138#>dest)<#40138#> <#40139#>true<#40139#><#40140#>]<#40140#>
<#40141#>[<#40141#><#40142#>else<#40142#> <#40143#>(route-exists?<#40143#> <#40144#>(neighbor<#40144#> <#40145#>orig<#40145#> <#40146#>sg)<#40146#> <#40147#>dest<#40147#> <#40148#>sg)]<#40148#><#40149#>))<#40149#>
<#71606#>;; <#67424#><#40157#>neighbor<#40157#> <#40158#>:<#40158#> <#40159#>node<#40159#> <#40160#>simple-graph<#40160#> <#40161#><#40161#><#40162#>-;SPMgt;<#40162#><#40163#><#40163#> <#40164#>node<#40164#><#67424#><#71606#>
<#71607#>;; to determine the node that is connected to <#67425#><#40165#>a-node<#40165#><#67425#> in <#67426#><#40166#>sg<#40166#><#67426#><#71607#>
<#40167#>(d<#40167#><#40168#>efine<#40168#> <#40169#>(neighbor<#40169#> <#40170#>a-node<#40170#> <#40171#>sg)<#40171#>
<#40172#>(c<#40172#><#40173#>ond<#40173#>
<#40174#>[<#40174#><#40175#>(empty?<#40175#> <#40176#>sg)<#40176#> <#40177#>(error<#40177#> <#40178#>``neighbor:<#40178#> <#40179#>impossible'')]<#40179#>
<#40180#>[<#40180#><#40181#>else<#40181#> <#40182#>(c<#40182#><#40183#>ond<#40183#>
<#40184#>[<#40184#><#40185#>(symbol=?<#40185#> <#40186#>(first<#40186#> <#40187#>(first<#40187#> <#40188#>sg))<#40188#> <#40189#>a-node)<#40189#>
<#40190#>(second<#40190#> <#40191#>(first<#40191#> <#40192#>sg))]<#40192#>
<#40193#>[<#40193#><#40194#>else<#40194#> <#40195#>(neighbor<#40195#> <#40196#>a-node<#40196#> <#40197#>(rest<#40197#> <#40198#>ag))]<#40198#><#40199#>)]<#40199#><#40200#>))<#40200#>
<#40204#>Figure: Finding a route in a simple graph (version 1)<#40204#>
Even a casual look at the function suggests that we have a
problem. Although the function is supposed to produce <#67427#><#40206#>false<#40206#><#67427#> if there
is no route from <#67428#><#40207#>orig<#40207#><#67428#> to <#67429#><#40208#>dest<#40208#><#67429#>, the function definition
doesn't contain <#67430#><#40209#>false<#40209#><#67430#> anywhere. Conversely, we need to ask what the
function actually does when there is no route between two nodes.
Take another look at figure~#figsimgraph#40210> <#40226#>(route-exists?<#40226#> <#40227#>'<#40227#><#40228#>C<#40228#> <#40229#>'<#40229#><#40230#>D<#40230#> <#40231#>'<#40231#><#40232#>((A<#40232#> <#40233#>B)<#40233#> <#40234#>(B<#40234#> <#40235#>C)<#40235#> <#40236#>(C<#40236#> <#40237#>E)<#40237#> <#40238#>(D<#40238#> <#40239#>E)<#40239#> <#40240#>(E<#40240#> <#40241#>B)<#40241#> <#40242#>(F<#40242#> <#40243#>F)))<#40243#>
<#40244#>=<#40244#> <#40245#>(route-exists?<#40245#> <#40246#>'<#40246#><#40247#>E<#40247#> <#40248#>'<#40248#><#40249#>D<#40249#> <#40250#>'<#40250#><#40251#>((A<#40251#> <#40252#>B)<#40252#> <#40253#>(B<#40253#> <#40254#>C)<#40254#> <#40255#>(C<#40255#> <#40256#>E)<#40256#> <#40257#>(D<#40257#> <#40258#>E)<#40258#> <#40259#>(E<#40259#> <#40260#>B)<#40260#> <#40261#>(F<#40261#> <#40262#>F)))<#40262#>
<#40263#>=<#40263#> <#40264#>(route-exists?<#40264#> <#40265#>'<#40265#><#40266#>B<#40266#> <#40267#>'<#40267#><#40268#>D<#40268#> <#40269#>'<#40269#><#40270#>((A<#40270#> <#40271#>B)<#40271#> <#40272#>(B<#40272#> <#40273#>C)<#40273#> <#40274#>(C<#40274#> <#40275#>E)<#40275#> <#40276#>(D<#40276#> <#40277#>E)<#40277#> <#40278#>(E<#40278#> <#40279#>B)<#40279#> <#40280#>(F<#40280#> <#40281#>F)))<#40281#>
<#40282#>=<#40282#> <#40283#>(route-exists?<#40283#> <#40284#>'<#40284#><#40285#>C<#40285#> <#40286#>'<#40286#><#40287#>D<#40287#> <#40288#>'<#40288#><#40289#>((A<#40289#> <#40290#>B)<#40290#> <#40291#>(B<#40291#> <#40292#>C)<#40292#> <#40293#>(C<#40293#> <#40294#>E)<#40294#> <#40295#>(D<#40295#> <#40296#>E)<#40296#> <#40297#>(E<#40297#> <#40298#>B)<#40298#> <#40299#>(F<#40299#> <#40300#>F)))<#40300#>
<#40301#>=<#40301#> <#40302#>...<#40302#>
The hand-evaluation confirms that as the function recurs, it calls itself
<#40306#>with the exact same arguments again and again.<#40306#> In other words, the
evaluation never stops.
Our problem with <#67435#><#40307#>route-exists?<#40307#><#67435#> is again a loss of ``knowledge,''
similar to that of <#67436#><#40308#>relative-2-absolute<#40308#><#67436#> in the preceding section.
Like <#67437#><#40309#>relative-2-absolute<#40309#><#67437#>, <#67438#><#40310#>route-exists?<#40310#><#67438#> was developed
according to the recipe and is independent of its context. That is, it
doesn't ``know'' whether some application is the first one or the 100th of
a long recursive chain. In the case of <#67439#><#40311#>route-exists?<#40311#><#67439#> this means,
in particular, that the function doesn't ``know'' whether a previous
application in the current chain of recursions received the exact same
arguments.
The solution follows the pattern of the preceding section. We add a
parameter, which we call <#67440#><#40312#>accu-seen<#40312#><#67440#> and which represents the
accumulated list of origination nodes that the function has encountered,
starting with the original application. Its initial value must be
<#67441#><#40313#>empty<#40313#><#67441#>. As the function checks on a specific <#67442#><#40314#>orig<#40314#><#67442#> and
moves to its neighbors, <#67443#><#40315#>orig<#40315#><#67443#> is added to <#67444#><#40316#>accu-seen<#40316#><#67444#>.
Here is a first revision of <#67445#><#40317#>route-exists?<#40317#><#67445#>, dubbed
<#67446#><#40318#>route-exists-accu?<#40318#><#67446#>:
<#71608#>;; <#67447#><#40323#>route-exists-accu?<#40323#> <#40324#>:<#40324#> <#40325#>node<#40325#> <#40326#>node<#40326#> <#40327#>simple-graph<#40327#> <#40328#>(listof<#40328#> <#40329#>node)<#40329#> <#40330#><#40330#><#40331#>-;SPMgt;<#40331#><#40332#><#40332#> <#40333#>boolean<#40333#><#67447#><#71608#>
<#71609#>;; to determine whether there is a route from <#67448#><#40334#>orig<#40334#><#67448#> to <#67449#><#40335#>dest<#40335#><#67449#> in <#67450#><#40336#>sg<#40336#><#67450#>, <#71609#>
<#71610#>;; assuming the nodes in <#67451#><#40337#>accu-seen<#40337#><#67451#><#71610#>
<#40338#>;; have already been inspected and failed to deliver a solution <#40338#>
<#40339#>(d<#40339#><#40340#>efine<#40340#> <#40341#>(route-exists-accu?<#40341#> <#40342#>orig<#40342#> <#40343#>dest<#40343#> <#40344#>sg<#40344#> <#40345#>accu-seen)<#40345#>
<#40346#>(c<#40346#><#40347#>ond<#40347#>
<#40348#>[<#40348#><#40349#>(symbol=?<#40349#> <#40350#>orig<#40350#> <#40351#>dest)<#40351#> <#40352#>true<#40352#><#40353#>]<#40353#>
<#40354#>[<#40354#><#40355#>else<#40355#> <#40356#>(route-exists-accu?<#40356#> <#40357#>(neighbor<#40357#> <#40358#>orig<#40358#> <#40359#>sg)<#40359#> <#40360#>dest<#40360#> <#40361#>sg<#40361#>
<#40362#>(cons<#40362#> <#40363#>orig<#40363#> <#40364#>accu-seen))]<#40364#><#40365#>))<#40365#>
The addition of the new parameter alone does not solve our problem, but, as
the following hand-evaluation shows, provides the foundation for one:
<#40373#>(route-exists-accu?<#40373#> <#40374#>'<#40374#><#40375#>C<#40375#> <#40376#>'<#40376#><#40377#>D<#40377#> <#40378#>'<#40378#><#40379#>((A<#40379#> <#40380#>B)<#40380#> <#40381#>(B<#40381#> <#40382#>C)<#40382#> <#40383#>(C<#40383#> <#40384#>E)<#40384#> <#40385#>(D<#40385#> <#40386#>E)<#40386#> <#40387#>(E<#40387#> <#40388#>B)<#40388#> <#40389#>(F<#40389#> <#40390#>F))<#40390#> <#40391#>empty)<#40391#>
<#40392#>=<#40392#> <#40393#>(route-exists-accu?<#40393#> <#40394#>'<#40394#><#40395#>E<#40395#> <#40396#>'<#40396#><#40397#>D<#40397#> <#40398#>'<#40398#><#40399#>((A<#40399#> <#40400#>B)<#40400#> <#40401#>(B<#40401#> <#40402#>C)<#40402#> <#40403#>(C<#40403#> <#40404#>E)<#40404#> <#40405#>(D<#40405#> <#40406#>E)<#40406#> <#40407#>(E<#40407#> <#40408#>B)<#40408#> <#40409#>(F<#40409#> <#40410#>F))<#40410#> <#40411#>'<#40411#><#40412#>(C))<#40412#>
<#40413#>=<#40413#> <#40414#>(route-exists-accu?<#40414#> <#40415#>'<#40415#><#40416#>B<#40416#> <#40417#>'<#40417#><#40418#>D<#40418#> <#40419#>'<#40419#><#40420#>((A<#40420#> <#40421#>B)<#40421#> <#40422#>(B<#40422#> <#40423#>C)<#40423#> <#40424#>(C<#40424#> <#40425#>E)<#40425#> <#40426#>(D<#40426#> <#40427#>E)<#40427#> <#40428#>(E<#40428#> <#40429#>B)<#40429#> <#40430#>(F<#40430#> <#40431#>F))<#40431#> <#40432#>'<#40432#><#40433#>(E<#40433#> <#40434#>C))<#40434#>
<#40435#>=<#40435#> <#40436#>(route-exists-accu?<#40436#> <#40437#>'<#40437#><#40438#>C<#40438#> <#40439#>'<#40439#><#40440#>D<#40440#> <#40441#>'<#40441#><#40442#>((A<#40442#> <#40443#>B)<#40443#> <#40444#>(B<#40444#> <#40445#>C)<#40445#> <#40446#>(C<#40446#> <#40447#>E)<#40447#> <#40448#>(D<#40448#> <#40449#>E)<#40449#> <#40450#>(E<#40450#> <#40451#>B)<#40451#> <#40452#>(F<#40452#> <#40453#>F))<#40453#>
<#40454#>'<#40454#><#40455#>(B<#40455#> <#40456#>E<#40456#> <#40457#>C))<#40457#>
In contrast to the original function, the revised function no longer calls
itself with the exact same arguments. While the three arguments proper are
again the same for the third recursive application, the accumulator
argument is different from that of the first application. Instead of
<#67452#><#40461#>empty<#40461#><#67452#>, it is now <#67453#><#40462#>'<#40462#><#40463#>(B<#40463#>\ <#40464#>E<#40464#>\ <#40465#>C)<#40465#><#67453#>. The new value represents the
fact that during the search of a route from <#67454#><#40466#>'<#40466#><#40467#>C<#40467#><#67454#> to <#67455#><#40468#>'<#40468#><#40469#>D<#40469#><#67455#>, the
function has inspected <#67456#><#40470#>'<#40470#><#40471#>B<#40471#><#67456#>, <#67457#><#40472#>'<#40472#><#40473#>E<#40473#><#67457#>, and <#67458#><#40474#>'<#40474#><#40475#>C<#40475#><#67458#> as starting
points.
All we need to do at this point, is exploit the accumulated knowledge in
the function definition. Specifically, we determine whether the given
<#67459#><#40476#>orig<#40476#><#67459#> is already an item on <#67460#><#40477#>accu-seen<#40477#><#67460#>. If so, the problem
is trivially solvable with <#67461#><#40478#>false<#40478#><#67461#>. Figure~#figrouteexists2#40479><#71611#>;; <#67465#><#40488#>route-exists2?<#40488#> <#40489#>:<#40489#> <#40490#>node<#40490#> <#40491#>node<#40491#> <#40492#>simple-graph<#40492#> <#40493#><#40493#><#40494#>-;SPMgt;<#40494#><#40495#><#40495#> <#40496#>boolean<#40496#><#67465#><#71611#>
<#71612#>;; to determine whether there is a route from <#67466#><#40497#>orig<#40497#><#67466#> to <#67467#><#40498#>dest<#40498#><#67467#> in <#67468#><#40499#>sg<#40499#><#67468#><#71612#>
<#40500#>(d<#40500#><#40501#>efine<#40501#> <#40502#>(route-exists2?<#40502#> <#40503#>orig<#40503#> <#40504#>dest<#40504#> <#40505#>sg)<#40505#>
<#40506#>(l<#40506#><#40507#>ocal<#40507#> <#40508#>((d<#40508#><#40509#>efine<#40509#> <#40510#>(re-accu?<#40510#> <#40511#>orig<#40511#> <#40512#>dest<#40512#> <#40513#>sg<#40513#> <#40514#>accu-seen)<#40514#>
<#40515#>(c<#40515#><#40516#>ond<#40516#>
<#40517#>[<#40517#><#40518#>(symbol=?<#40518#> <#40519#>orig<#40519#> <#40520#>dest)<#40520#> <#40521#>true<#40521#><#40522#>]<#40522#>
<#40523#>[<#40523#><#40524#>(contains<#40524#> <#40525#>orig<#40525#> <#40526#>accu-seen)<#40526#> <#40527#>false<#40527#><#40528#>]<#40528#>
<#40529#>[<#40529#><#40530#>else<#40530#> <#40531#>(re-accu?<#40531#> <#40532#>(neighbor<#40532#> <#40533#>orig<#40533#> <#40534#>sg)<#40534#> <#40535#>dest<#40535#> <#40536#>sg<#40536#> <#40537#>(cons<#40537#> <#40538#>orig<#40538#> <#40539#>accu-seen))]<#40539#><#40540#>)))<#40540#>
<#40541#>(re-accu?<#40541#> <#40542#>orig<#40542#> <#40543#>dest<#40543#> <#40544#>sg<#40544#> <#40545#>empty)))<#40545#>
<#40549#>Figure: Finding a route in a simple graph (version~2)<#40549#>
The definition of <#67469#><#40551#>route-exists2?<#40551#><#67469#> also eliminates the two minor
problems with the first revision. By <#67470#><#40552#>local<#40552#><#67470#>izing the definition of
the accumulating function, we can ensure that the first call to
<#67471#><#40553#>re-accu?<#40553#><#67471#> always uses <#67472#><#40554#>empty<#40554#><#67472#> as the initial value for
<#67473#><#40555#>accu-seen<#40555#><#67473#>. And, <#67474#><#40556#>route-exists2?<#40556#><#67474#> satisfies the exact same
contract and purpose statement as <#67475#><#40557#>route-exists?<#40557#><#67475#>.
Still, there is a significant difference between <#67476#><#40558#>route-exists2?<#40558#><#67476#>
and <#67477#><#40559#>relative-to-absolute2<#40559#><#67477#>. Whereas the latter was equivalent to
the original function, <#67478#><#40560#>route-exists2?<#40560#><#67478#> is an improvement over the
<#67479#><#40561#>route-exists?<#40561#><#67479#> function. After all, it corrects a fundamental flaw
in <#67480#><#40562#>route-exists?<#40562#><#67480#>, which completely failed to find an answer for
some inputs.
<#40565#>Exercise 30.2.1<#40565#>