Functions that affect the memory of a program may not only process simple forms
of data but also arbitrarily large pieces of data. To understand how this works,
let us take a closer look at the purpose of <#68613#><#47493#>reveal-list<#47493#><#68613#> from the
hangman game program.
As we have just seen, the function compares <#68614#><#47494#>guess<#47494#><#68614#> with each letter
in <#68615#><#47495#>chosen-word<#47495#><#68615#>. If it is the same, <#68616#><#47496#>guess<#47496#><#68616#> may uncover new
knowledge and is included at the appropriate position in the word;
otherwise, the corresponding letter from <#68617#><#47497#>status-word<#47497#><#68617#> represents
what the player knows.
The <#68618#><#47498#>hangman-guess<#47498#><#68618#> function then compares the result of
<#68619#><#47499#>reveal-list<#47499#><#68619#> with the old value of <#68620#><#47500#>status-word<#47500#><#68620#> to find out
whether the player uncovered new knowledge. Furthermore, the result is
compared with <#68621#><#47501#>chosen-word<#47501#><#68621#> again if the player found new knowledge,
because <#68622#><#47502#>guess<#47502#><#68622#> might have matched all remaining unknown
letters. Clearly, both of these comparisons repeat the computations of
<#68623#><#47503#>reveal-one<#47503#><#68623#>. The problem is that the result of <#68624#><#47504#>reveal-one<#47504#><#68624#>
is useful to <#68625#><#47505#>reveal-list<#47505#><#68625#> and that the result of its individual
comparisons are useful in the conditionals of <#68626#><#47506#>hangman-guess<#47506#><#68626#>.
We can solve the first part of the problem with the use of an additional
piece of memory: a state variable that records whether <#68627#><#47507#>reveal-one<#47507#><#68627#>
uncovers a letter. The state variable, let's call it
<#68628#><#47508#>new-knowledge<#47508#><#68628#>, is modified by <#68629#><#47509#>reveal-one<#47509#><#68629#> if it determines
that <#68630#><#47510#>guess<#47510#><#68630#> uncovers a currently hidden letter in
<#68631#><#47511#>chosen-word<#47511#><#68631#>. The <#68632#><#47512#>hangman-guess<#47512#><#68632#> function can use
<#68633#><#47513#>new-knowledge<#47513#><#68633#> to find out what <#68634#><#47514#>reveal-one<#47514#><#68634#> discovered.
Let us now translate our idea into new program definitions systematically.
First, we need to specify the state variable and its meaning:
<#71799#>;; <#68635#><#47519#>new-knowledge<#47519#> <#47520#>:<#47520#> <#47521#>boolean<#47521#><#68635#><#71799#>
<#47522#>;; the variable represents whether the most recent application of<#47522#>
<#71800#>;; <#68636#><#47523#>reveal-list<#47523#><#68636#> has provided the player with new knowledge<#71800#>
<#47524#>(define<#47524#> <#47525#>new-knowledge<#47525#> <#47526#>false)<#47526#>
Second, we must consider what it means to initialize the new state
variable. From what we know, the state variable is used every time
<#68637#><#47530#>reveal-list<#47530#><#68637#> is applied to <#68638#><#47531#>guess<#47531#><#68638#>. When the application
starts, the state variable should be <#68639#><#47532#>false<#47532#><#68639#>; it should change to
<#68640#><#47533#>true<#47533#><#68640#> if <#68641#><#47534#>guess<#47534#><#68641#> is useful. This suggests that
<#68642#><#47535#>new-knowledge<#47535#><#68642#> is to be initialized to <#68643#><#47536#>false<#47536#><#68643#> every time
<#68644#><#47537#>reveal-list<#47537#><#68644#> is applied. We can achieve this re-initialization by
changing <#68645#><#47538#>reveal-list<#47538#><#68645#> so that it sets the state variable before it
computes anything else:
<#71801#>;; <#68646#><#47543#>reveal-list<#47543#> <#47544#>:<#47544#> <#47545#>word<#47545#> <#47546#>word<#47546#> <#47547#>letter<#47547#> <#47548#><#47548#><#47549#>-;SPMgt;<#47549#><#47550#><#47550#> <#47551#>word<#47551#><#68646#><#71801#>
<#47552#>;; to compute the new status word<#47552#>
<#71802#>;; effect: to set <#68647#><#47553#>new-knowledge<#47553#><#68647#> to <#68648#><#47554#>false<#47554#><#68648#> first<#71802#>
<#47555#>(d<#47555#><#47556#>efine<#47556#> <#47557#>(reveal-list<#47557#> <#47558#>chosen-word<#47558#> <#47559#>status-word<#47559#> <#47560#>guess)<#47560#>
<#47561#>(l<#47561#><#47562#>ocal<#47562#> <#47563#>((define<#47563#> <#47564#>(reveal-one<#47564#> <#47565#>chosen-letter<#47565#> <#47566#>status-letter)<#47566#> <#47567#>...))<#47567#>
<#47568#>(b<#47568#><#47569#>egin<#47569#>
<#72348#>#tex2html_wrap_inline74096#<#72348#>
<#47573#>(map<#47573#> <#47574#>reveal-one<#47574#> <#47575#>chosen-word<#47575#> <#47576#>status-word))))<#47576#>
The underlined expression is the essential modification. The <#68650#><#47580#>local<#47580#><#68650#>
expression defines the auxiliary function <#68651#><#47581#>reveal-one<#47581#><#68651#> and then
evaluates the <#68652#><#47582#>local<#47582#><#68652#>'s body. The first step of the body is to
initialize <#68653#><#47583#>new-knowledge<#47583#><#68653#>.
Third, we must develop the program that modifies <#68654#><#47584#>new-knowledge<#47584#><#68654#>. Here
the program already exists: <#68655#><#47585#>reveal-list<#47585#><#68655#>, so our task is to modify it
in such a way that it changes the state variable appropriately. Let's describe
the idea with a modified effect statement:
<#71804#>;; <#68656#><#47590#>reveal-list<#47590#> <#47591#>:<#47591#> <#47592#>word<#47592#> <#47593#>word<#47593#> <#47594#>letter<#47594#> <#47595#><#47595#><#47596#>-;SPMgt;<#47596#><#47597#><#47597#> <#47598#>word<#47598#><#68656#><#71804#>
<#47599#>;; to compute the new status word<#47599#>
<#47600#>;; effect: <#47600#>
<#71805#>;; (1) to set <#68657#><#47601#>new-knowledge<#47601#><#68657#> to <#68658#><#47602#>false<#47602#><#68658#> first<#71805#>
<#71806#>;; (2) to set <#68659#><#47603#>new-knowledge<#47603#><#68659#> to <#68660#><#47604#>true<#47604#><#68660#> if <#68661#><#47605#>guess<#47605#><#68661#> reveals new knowledge<#71806#>
The first part of the effect is necessary for the second one; an experienced
programmer may drop it.
Next we should modify the examples for the function to illustrate what kind
of effects happen. The purpose of the function is to compute the new status
word by checking whether <#68662#><#47609#>guess<#47609#><#68662#> occurs in the
<#68663#><#47610#>chosen-word<#47610#><#68663#>. There are two basic situations depending on whether
<#68664#><#47611#>guess<#47611#><#68664#> reveals new knowledge or not:
-
If <#68665#><#47613#>status-word<#47613#><#68665#> is <#68666#><#47614#>(list<#47614#>\ <#47615#>'<#47615#><#47616#>b<#47616#>\ <#47617#>'<#47617#><#47618#>_<#47618#>\ <#47619#>'<#47619#><#47620#>l<#47620#>\ <#47621#>'<#47621#><#47622#>l)<#47622#><#68666#> and
<#68667#><#47623#>chosen-word<#47623#><#68667#> is <#68668#><#47624#>(list<#47624#>\ <#47625#>'<#47625#><#47626#>b<#47626#>\ <#47627#>'<#47627#><#47628#>a<#47628#>\ <#47629#>'<#47629#><#47630#>l<#47630#>\ <#47631#>'<#47631#><#47632#>l)<#47632#><#68668#>, then evaluating
<#47637#>(reveal-one<#47637#> <#47638#>chosen-wor<#47638#> <#47639#>status-word<#47639#> <#47640#>'<#47640#><#47641#>a)<#47641#>
produces <#68669#><#47645#>(list<#47645#>\ <#47646#>'<#47646#><#47647#>b<#47647#>\ <#47648#>'<#47648#><#47649#>a<#47649#>\ <#47650#>'<#47650#><#47651#>l<#47651#>\ <#47652#>'<#47652#><#47653#>l)<#47653#><#68669#> and <#68670#><#47654#>new-knowledge<#47654#><#68670#> is <#68671#><#47655#>true<#47655#><#68671#>.
-
If <#68672#><#47656#>status-word<#47656#><#68672#> is <#68673#><#47657#>(list<#47657#>\ <#47658#>'<#47658#><#47659#>b<#47659#>\ <#47660#>'<#47660#><#47661#>_<#47661#>\ <#47662#>'<#47662#><#47663#>_<#47663#>\ <#47664#>'<#47664#><#47665#>_<#47665#><#47666#>)<#47666#><#68673#> and
<#68674#><#47667#>chosen-word<#47667#><#68674#> is <#68675#><#47668#>(list<#47668#>\ <#47669#>'<#47669#><#47670#>b<#47670#>\ <#47671#>'<#47671#><#47672#>a<#47672#>\ <#47673#>'<#47673#><#47674#>l<#47674#>\ <#47675#>'<#47675#><#47676#>l)<#47676#><#68675#>, then evaluating
<#47681#>(reveal-one<#47681#> <#47682#>chosen-wor<#47682#> <#47683#>status-word<#47683#> <#47684#>'<#47684#><#47685#>x)<#47685#>
produces <#68676#><#47689#>(list<#47689#>\ <#47690#>'<#47690#><#47691#>b<#47691#>\ <#47692#>'<#47692#><#47693#>_<#47693#>\ <#47694#>'<#47694#><#47695#>_<#47695#>\ <#47696#>'<#47696#><#47697#>_<#47697#><#47698#>)<#47698#><#68676#> and <#68677#><#47699#>new-knowledge<#47699#><#68677#> is <#68678#><#47700#>false<#47700#><#68678#>.
-
If <#68679#><#47701#>status-word<#47701#><#68679#> is <#68680#><#47702#>(list<#47702#>\ <#47703#>'<#47703#><#47704#>b<#47704#>\ <#47705#>'<#47705#><#47706#>_<#47706#>\ <#47707#>'<#47707#><#47708#>_<#47708#>\ <#47709#>'<#47709#><#47710#>_<#47710#><#47711#>)<#47711#><#68680#> and
<#68681#><#47712#>chosen-word<#47712#><#68681#> is <#68682#><#47713#>(list<#47713#>\ <#47714#>'<#47714#><#47715#>b<#47715#>\ <#47716#>'<#47716#><#47717#>a<#47717#>\ <#47718#>'<#47718#><#47719#>l<#47719#>\ <#47720#>'<#47720#><#47721#>l)<#47721#><#68682#>, then evaluating
<#47726#>(reveal-one<#47726#> <#47727#>chosen-wor<#47727#> <#47728#>status-word<#47728#> <#47729#>'<#47729#><#47730#>l)<#47730#>
produces <#68683#><#47734#>(list<#47734#>\ <#47735#>'<#47735#><#47736#>b<#47736#>\ <#47737#>'<#47737#><#47738#>_<#47738#>\ <#47739#>'<#47739#><#47740#>l<#47740#>\ <#47741#>'<#47741#><#47742#>l)<#47742#><#68683#> and <#68684#><#47743#>new-knowledge<#47743#><#68684#> is <#68685#><#47744#>true<#47744#><#68685#>.
-
Finally, if <#68686#><#47745#>status-word<#47745#><#68686#> is <#68687#><#47746#>(list<#47746#>\ <#47747#>'<#47747#><#47748#>b<#47748#>\ <#47749#>'<#47749#><#47750#>_<#47750#>\ <#47751#>'<#47751#><#47752#>l<#47752#>\ <#47753#>'<#47753#><#47754#>l)<#47754#><#68687#> and
<#68688#><#47755#>chosen-word<#47755#><#68688#> is <#68689#><#47756#>(list<#47756#>\ <#47757#>'<#47757#><#47758#>b<#47758#>\ <#47759#>'<#47759#><#47760#>a<#47760#>\ <#47761#>'<#47761#><#47762#>l<#47762#>\ <#47763#>'<#47763#><#47764#>l)<#47764#><#68689#>, then evaluating
<#47769#>(reveal-one<#47769#> <#47770#>chosen-wor<#47770#> <#47771#>status-word<#47771#> <#47772#>'<#47772#><#47773#>l)<#47773#>
produces <#68690#><#47777#>(list<#47777#>\ <#47778#>'<#47778#><#47779#>b<#47779#>\ <#47780#>'<#47780#><#47781#>_<#47781#>\ <#47782#>'<#47782#><#47783#>l<#47783#>\ <#47784#>'<#47784#><#47785#>l)<#47785#><#68690#> and <#68691#><#47786#>new-knowledge<#47786#><#68691#> is <#68692#><#47787#>false<#47787#><#68692#>.
The first two examples cover the basic situations; the third one shows that
if <#68693#><#47789#>guess<#47789#><#68693#> reveals several new positions in the word,
<#68694#><#47790#>new-knowledge<#47790#><#68694#> also becomes <#68695#><#47791#>true<#47791#><#68695#>; and the last shows how
guessing a letter that has been uncovered before means no new knowledge has
been added.
Given that we already have a function, we can skip the template step and
instead focus on the question what we need to change in the existing
function. The given version of <#68696#><#47792#>reveal-list<#47792#><#68696#> maps <#68697#><#47793#>reveal-one<#47793#><#68697#>
over the two words, which are lists of letters. It is <#68698#><#47794#>reveal-one<#47794#><#68698#>
that compares <#68699#><#47795#>guess<#47795#><#68699#> with the letters in <#68700#><#47796#>chosen-word<#47796#><#68700#> and
that determines whether the player has uncovered new knowledge. Hence, we
must modify the auxiliary function so that it recognizes when <#68701#><#47797#>guess<#47797#><#68701#>
represents new knowledge and to set <#68702#><#47798#>new-knowledge<#47798#><#68702#> to true in that
case.
As it is currently defined, <#68703#><#47799#>reveal-one<#47799#><#68703#> merely compares
<#68704#><#47800#>guess<#47800#><#68704#> with the letters in <#68705#><#47801#>chosen-word<#47801#><#68705#>. It does not check
whether the player discovers truly new knowledge if <#68706#><#47802#>guess<#47802#><#68706#> and
<#68707#><#47803#>chosen-letter<#47803#><#68707#> are the same. The letter <#68708#><#47804#>guess<#47804#><#68708#>, however,
represents new knowledge only if the matching letter in the <#47805#>status<#47805#> word
is still <#68709#><#47806#>'<#47806#><#47807#>_<#47807#><#68709#>. This suggests the following two modifications:
<#71807#>;; <#68710#><#47812#>reveal-list<#47812#> <#47813#>:<#47813#> <#47814#>word<#47814#> <#47815#>word<#47815#> <#47816#>letter<#47816#> <#47817#><#47817#><#47818#>-;SPMgt;<#47818#><#47819#><#47819#> <#47820#>word<#47820#><#68710#><#71807#>
<#47821#>;; to compute the new status word<#47821#>
<#71808#>;; effect: to set <#68711#><#47822#>new-knowledge<#47822#><#68711#> to <#68712#><#47823#>true<#47823#><#68712#> if <#68713#><#47824#>guess<#47824#><#68713#> reveals new knowledge<#71808#>
<#47825#>(d<#47825#><#47826#>efine<#47826#> <#47827#>(reveal-list<#47827#> <#47828#>chosen-word<#47828#> <#47829#>status-word<#47829#> <#47830#>guess)<#47830#>
<#47831#>(l<#47831#><#47832#>ocal<#47832#> <#47833#>((d<#47833#><#47834#>efine<#47834#> <#47835#>(reveal-one<#47835#> <#47836#>chosen-letter<#47836#> <#47837#>status-letter)<#47837#>
<#47838#>(c<#47838#><#47839#>ond<#47839#>
<#47840#>[<#47840#><#47841#>(and<#47841#> <#47842#>(symbol=?<#47842#> <#47843#>chosen-letter<#47843#> <#47844#>guess)<#47844#>
<#72349#>#tex2html_wrap_inline74098#<#72349#><#47850#>)<#47850#>
<#47851#>(b<#47851#><#47852#>egin<#47852#>
<#72350#>#tex2html_wrap_inline74100#<#72350#>
<#47856#>guess)]<#47856#>
<#47857#>[<#47857#><#47858#>else<#47858#> <#47859#>status-letter]<#47859#><#47860#>)))<#47860#>
<#47861#>(b<#47861#><#47862#>egin<#47862#>
<#47863#>(set!<#47863#> <#47864#>new-knowledge<#47864#> <#47865#>false)<#47865#>
<#47866#>(map<#47866#> <#47867#>reveal-one<#47867#> <#47868#>chosen-word<#47868#> <#47869#>status-word))))<#47869#>
That is, <#68716#><#47873#>reveal-one<#47873#><#68716#> changes the value of <#68717#><#47874#>new-knowledge<#47874#><#68717#>
if, and only if, both <#68718#><#47875#>(symbol=?<#47875#>\ <#47876#>chosen-letter<#47876#>\ <#47877#>guess)<#47877#><#68718#> and <#68719#><#47878#>(symbol=?<#47878#><#47879#> <#47879#><#47880#>status-letter<#47880#>\ <#47881#>'<#47881#><#47882#>_<#47882#><#47883#>)<#47883#><#68719#> are true.
In summary, we can use state variables if we wish to communicate several
results from one computation to distant places. For such cases, the
interface of a function is under our control but we choose to design it
such that the function has both a result and an effect. The proper way to
achieve these combinations is to develop the computations separately and to
merge them later, if necessary.
<#47886#>Exercise 37.3.1<#47886#>
Draw a diagram that shows how <#68720#><#47888#>hangman<#47888#><#68720#>, <#68721#><#47889#>hangman-guess<#47889#><#68721#>, and
<#68722#><#47890#>reveal-list<#47890#><#68722#> interact with the state
variables.~ Solution<#68723#><#68723#>
<#47896#>Exercise 37.3.2<#47896#>
Turn the three examples into tests, that is, boolean-valued expressions, and test
the new version of <#68724#><#47898#>reveal-list<#47898#><#68724#>. How many times does
<#68725#><#47899#>reveal-one<#47899#><#68725#> modify <#68726#><#47900#>new-knowledge<#47900#><#68726#> for the third test
case?~ Solution<#68727#><#68727#>
<#47906#>Exercise 37.3.3<#47906#>
Modify <#68728#><#47908#>hangman-guess<#47908#><#68728#> in the hangman program to take advantage of the
additional information that <#68729#><#47909#>reveal-list<#47909#><#68729#> provides through
<#68730#><#47910#>new-knowledge<#47910#><#68730#>.~ Solution<#68731#><#68731#>
<#47916#>Exercise 37.3.4<#47916#>
Modify the hangman program a second time to eliminate the second
<#68732#><#47918#>equal?<#47918#><#68732#> in <#68733#><#47919#>hangman-guess<#47919#><#68733#>. <#47920#>Hint:<#47920#> \ Introduce a state variable
that counts how many letters the player doesn't know yet.~ Solution<#68734#><#68734#>
Let us study a second example of a function that consumes an arbitrarily
large piece of data and modifies the program's memory. The example is a
natural extension of the traffic light simulator in
section~#secdesignmemory#47928>. We developed two functions:
<#71811#>;; <#68735#><#47933#>init-traffic-light<#47933#> <#47934#>:<#47934#> <#47935#><#47935#><#47936#>-;SPMgt;<#47936#><#47937#><#47937#> <#47938#>void<#47938#><#68735#> <#71811#>
<#71812#>;; effects: (1) to initialize <#68736#><#47939#>current-color<#47939#><#68736#>; (2) to draw traffic light<#71812#>
and
<#71813#>;; <#68737#><#47947#>next<#47947#> <#47948#>:<#47948#> <#47949#><#47949#><#47950#>-;SPMgt;<#47950#><#47951#><#47951#> <#47952#>void<#47952#><#68737#><#71813#>
<#71814#>;; <#47953#>effects<#47953#>: (1) to change <#68738#><#47954#>current-color<#47954#><#68738#> from <#68739#><#47955#>'<#47955#><#47956#>green<#47956#><#68739#> to <#68740#><#47957#>'<#47957#><#47958#>yellow<#47958#><#68740#>, <#71814#>
<#71815#>;; <#68741#><#47959#>'<#47959#><#47960#>yellow<#47960#><#68741#> to <#68742#><#47961#>'<#47961#><#47962#>red<#47962#><#68742#>, and <#68743#><#47963#>'<#47963#><#47964#>red<#47964#><#68743#> to <#68744#><#47965#>'<#47965#><#47966#>green<#47966#><#68744#><#71815#>
<#47967#>;; (2) to re-draw the traffic light appropriately <#47967#>
The first one starts the process; with the second one, we can repeatedly
switch the state of the light by evaluating <#68745#><#47971#>(next)<#47971#><#68745#> in the
<#47972#>Interactions<#47972#> window.
Typing in <#68746#><#47973#>(next)<#47973#><#68746#> over and over again is tiring, so it is natural
to wonder how to write a program that switches the state of the traffic
light a 100 or 1000 or 10000 times. In other words, we should develop a
program---let's call it <#68747#><#47974#>switch<#47974#><#68747#>---that consumes a natural number
and that switches the light from one color to another that many times.
The function consumes a natural number and produces <#68748#><#47975#>(<#47975#><#47976#>void<#47976#><#47977#>)<#47977#><#68748#>, after it
succeeded in switching the traffic light a sufficient number of times. By
now we can immediately write down all the basics, including the template,
for a function that consumes a natural number:
<#71816#>;; <#68749#><#47982#>switch<#47982#> <#47983#>:<#47983#> <#47984#>N<#47984#> <#47985#><#47985#><#47986#>-;SPMgt;<#47986#><#47987#><#47987#> <#47988#>void<#47988#><#68749#><#71816#>
<#47989#>;; purpose: it computes nothing of interest<#47989#>
<#71817#>;; effect: switch the traffic light <#68750#><#47990#>n<#47990#><#68750#> times, <#71817#>
<#47991#>;; holding each color for three seconds<#47991#>
<#47992#>(d<#47992#><#47993#>efine<#47993#> <#47994#>(switch<#47994#> <#47995#>n)<#47995#>
<#47996#>(c<#47996#><#47997#>ond<#47997#>
<#47998#>[<#47998#><#47999#>(zero?<#47999#> <#48000#>n)<#48000#> <#48001#>...]<#48001#>
<#48002#>[<#48002#><#48003#>else<#48003#> <#48004#>...<#48004#> <#48005#>(switch<#48005#> <#48006#>(-<#48006#> <#48007#>n<#48007#> <#48008#>1))<#48008#> <#48009#>...]<#48009#><#48010#>))<#48010#>
The template is that of a conventional, structurally recursive function.
Making up an example is also straightforward. If we evaluate <#68751#><#48014#>(switch<#48014#><#48015#> <#48015#><#48016#>4)<#48016#><#68751#>, we wish to see a change from <#68752#><#48017#>'<#48017#><#48018#>red<#48018#><#68752#> to <#68753#><#48019#>'<#48019#><#48020#>yellow<#48020#><#68753#>,
<#68754#><#48021#>'<#48021#><#48022#>green<#48022#><#68754#>, and <#68755#><#48023#>'<#48023#><#48024#>red<#48024#><#68755#> again, with each stage visible for three
seconds.
Defining the full function based on the template is straightforward. We
proceed by cases. If <#68756#><#48025#>n<#48025#><#68756#> is <#68757#><#48026#>0<#48026#><#68757#>, the answer is
<#68758#><#48027#>(<#48027#><#48028#>void<#48028#><#48029#>)<#48029#><#68758#>. Otherwise, we know that
<#48034#>(switch<#48034#> <#48035#>(-<#48035#> <#48036#>n<#48036#> <#48037#>1))<#48037#>
simulates all the necessary switching actions but one. To accomplish this
one additional switch, the function must use <#68759#><#48041#>(next)<#48041#><#68759#> to perform all
the state changes and the change of canvas and must wait three seconds. If
we put everything together in a <#68760#><#48042#>begin<#48042#>-expression<#68760#>, things happen in
the right order:
<#48047#>(begin<#48047#> <#48048#>(sleep-for-a-while<#48048#> <#48049#>3)<#48049#>
<#48050#>(next)<#48050#>
<#48051#>(switch<#48051#> <#48052#>(-<#48052#> <#48053#>n<#48053#> <#48054#>1)))<#48054#>
The top of figure~#figswitching#48058> is the complete definition for
<#68761#><#48059#>switch<#48059#><#68761#>.
<#71818#>;; <#68762#><#48064#>switch<#48064#> <#48065#>:<#48065#> <#48066#>N<#48066#> <#48067#><#48067#><#48068#>-;SPMgt;<#48068#><#48069#><#48069#> <#48070#>void<#48070#><#68762#><#71818#>
<#71819#>;; effect: switch the traffic light <#68763#><#48071#>n<#48071#><#68763#> times, holding each color for <#68764#><#48072#>3<#48072#><#68764#> seconds<#71819#>
<#48073#>;; structural recursion <#48073#>
<#48074#>(d<#48074#><#48075#>efine<#48075#> <#48076#>(switch<#48076#> <#48077#>n)<#48077#>
<#48078#>(c<#48078#><#48079#>ond<#48079#>
<#48080#>[<#48080#><#48081#>(=<#48081#> <#48082#>n<#48082#> <#48083#>0)<#48083#> <#48084#>(<#48084#><#48085#>void<#48085#><#48086#>)]<#48086#>
<#48087#>[<#48087#><#48088#>else<#48088#> <#48089#>(begin<#48089#> <#48090#>(sleep-for-a-while<#48090#> <#48091#>3)<#48091#>
<#48092#>(next)<#48092#>
<#48093#>(switch<#48093#> <#48094#>(-<#48094#> <#48095#>n<#48095#> <#48096#>1)))]<#48096#><#48097#>))<#48097#>
<#71820#>;; <#68765#><#48105#>switch-forever<#48105#> <#48106#>:<#48106#> <#48107#><#48107#><#48108#>-;SPMgt;<#48108#><#48109#><#48109#> <#48110#>void<#48110#><#68765#><#71820#>
<#71821#>;; effect: switch the traffic light forever, holding each color for <#68766#><#48111#>3<#48111#><#68766#> seconds<#71821#>
<#48112#>;; generative recursion <#48112#>
<#48113#>(d<#48113#><#48114#>efine<#48114#> <#48115#>(switch-forever)<#48115#>
<#48116#>(begin<#48116#> <#48117#>(sleep-for-a-while<#48117#> <#48118#>3)<#48118#>
<#48119#>(next)<#48119#>
<#48120#>(switch-forever)))<#48120#>
<#48124#>Figure: Two ways of switching traffic lights<#48124#>
An alternative is to switch the traffic light forever or at least until it
breaks due to some external event. In this case, the simulator does not
consume any argument and, when applied, runs forever. This is the simplest
form of generative recursion we can possibly encounter:
<#71822#>;; <#68767#><#48130#>switch-forever<#48130#> <#48131#>:<#48131#> <#48132#><#48132#><#48133#>-;SPMgt;<#48133#><#48134#><#48134#> <#48135#>void<#48135#><#68767#><#71822#>
<#48136#>;; effect: switch the traffic light forever, <#48136#>
<#71823#>;; holding each color for <#68768#><#48137#>3<#48137#><#68768#> seconds<#71823#>
<#48138#>(d<#48138#><#48139#>efine<#48139#> <#48140#>(switch-forever)<#48140#>
<#48141#>...<#48141#>
<#48142#>(switch-forever))<#48142#>
Because the program does not terminate under any conditions, the template
contains only one recursive call. This suffices to construct an eternally
looping function.
Using this template, we can define the complete function as before. Before
recurring, the function must sleep and switch the light with <#68769#><#48146#>next<#48146#><#68769#>.
We can accomplish this with a <#68770#><#48147#>begin<#48147#>-expression<#68770#>, as shown in the
bottom definition of figure~#figswitching#48148>.
In summary, when we must develop recursive functions that modify the
program's memory, we choose the design recipe that best matches our
situation and proceed accordingly. In particular, if the function has both
an interesting purpose and an effect, as for example <#68771#><#48149#>reveal-list<#48149#><#68771#>,
we should first develop the pure function and then add the effects later.
<#48152#>Exercise 37.3.5<#48152#>
In section~#seclossgenerative#48154>, we discussed how to search for routes
in simple graphs. The Scheme representation of a simple graph is a list of
pairs (of symbols). The pairs specify the direct connections among the
nodes in the graph. Each node is the beginning of exactly one connection,
but may be the end of several such connections or none. Given two nodes in
a simple graph, the problem is to find out whether one can go from the
first to the second.
Recall is our first attempt at a function that determines whether the route
exists (see also figure~#figrouteexists1#48155>):
<#71824#>;; <#68772#><#48160#>route-exists?<#48160#> <#48161#>:<#48161#> <#48162#>node<#48162#> <#48163#>node<#48163#> <#48164#>simple-graph<#48164#> <#48165#><#48165#><#48166#>-;SPMgt;<#48166#><#48167#><#48167#> <#48168#>boolean<#48168#><#68772#><#71824#>
<#71825#>;; to determine whether there is a route from <#68773#><#48169#>orig<#48169#><#68773#> to <#68774#><#48170#>dest<#48170#><#68774#> in <#68775#><#48171#>sg<#48171#><#68775#><#71825#>
<#48172#>;; generative recursion <#48172#>
<#48173#>(d<#48173#><#48174#>efine<#48174#> <#48175#>(route-exists?<#48175#> <#48176#>orig<#48176#> <#48177#>dest<#48177#> <#48178#>sg)<#48178#>
<#48179#>(c<#48179#><#48180#>ond<#48180#>
<#48181#>[<#48181#><#48182#>(symbol=?<#48182#> <#48183#>orig<#48183#> <#48184#>dest)<#48184#> <#48185#>true<#48185#><#48186#>]<#48186#>
<#48187#>[<#48187#><#48188#>else<#48188#> <#48189#>(route-exists?<#48189#> <#48190#>(neighbor<#48190#> <#48191#>orig<#48191#> <#48192#>sg)<#48192#> <#48193#>dest<#48193#> <#48194#>sg)]<#48194#><#48195#>))<#48195#>
The function checks whether the origination and destination nodes are the
same. If not, it generates a new problem by looking up the neighbor of the
origination node in the graph.
On occasion, <#68776#><#48199#>route-exists?<#48199#><#68776#> fails to produce an answer if the graph
contains a cycle. In section~#seclossgenerative#48200> we solved the
problem with an accumulator. It is also possible to solve it with a state
variable that keeps track of the origination nodes that
<#68777#><#48201#>route-exists?<#48201#><#68777#> has visited for one particular attempt. Modify the
function appropriately.~ Solution<#68778#><#68778#>
<#48207#>Exercise 37.3.6<#48207#>
In section~#secfilesmodels#48209>, we developed several simple models of
a computer's file system. Develop the function <#68779#><#48210#>dir-listing<#48210#><#68779#>, which
consumes a directory and produces a list of all file names in the directory
and all of its subdirectories. The function also sets the state variable
<#68780#><#48211#>how-many-directories<#48211#><#68780#> to the number of subdirectories it encounters
during the process.~ Solution<#68781#><#68781#>