The template for algorithms is so general that it even covers functions
based on structural recursion. Consider the version with one termination
clause and one generation step:
<#33956#>(d<#33956#><#33957#>efine<#33957#> <#33958#>(generative-recursive-fun<#33958#> <#33959#>problem)<#33959#>
<#33960#>(c<#33960#><#33961#>ond<#33961#>
<#33962#>[<#33962#><#33963#>(trivially-solvable?<#33963#> <#33964#>problem)<#33964#>
<#33965#>(determine-solution<#33965#> <#33966#>problem)]<#33966#>
<#33967#>[<#33967#><#33968#>e<#33968#><#33969#>lse<#33969#>
<#33970#>(c<#33970#><#33971#>ombine-solutions<#33971#>
<#33972#>problem<#33972#>
<#33973#>(generative-recursive-fun<#33973#> <#33974#>(generate-problem<#33974#> <#33975#>problem)))]<#33975#><#33976#>))<#33976#>
If we replace <#66305#><#33980#>trivially-solvable?<#33980#><#66305#> with <#66306#><#33981#>empty?<#33981#><#66306#> and
<#66307#><#33982#>generate-problem<#33982#><#66307#> with <#66308#><#33983#>rest<#33983#><#66308#>, the outline <#66309#><#33984#>is<#33984#><#66309#> a
template for a list-processing function:
<#33989#>(d<#33989#><#33990#>efine<#33990#> <#33991#>(generative-recursive-fun<#33991#> <#33992#>problem)<#33992#>
<#33993#>(c<#33993#><#33994#>ond<#33994#>
<#33995#>[<#33995#><#33996#>(empty?<#33996#> <#33997#>problem)<#33997#> <#33998#>(determine-solution<#33998#> <#33999#>problem)]<#33999#>
<#34000#>[<#34000#><#34001#>e<#34001#><#34002#>lse<#34002#>
<#34003#>(c<#34003#><#34004#>ombine-solutions<#34004#>
<#34005#>problem<#34005#>
<#34006#>(generative-recursive-fun<#34006#> <#34007#>(rest<#34007#> <#34008#>problem)))]<#34008#><#34009#>))<#34009#>
<#34015#>Exercise 26.2.1<#34015#>
Define <#66310#><#34017#>determine-solution<#34017#><#66310#> and <#66311#><#34018#>combine-solutions<#34018#><#66311#> so that
the function <#66312#><#34019#>generative-recursive-fun<#34019#><#66312#> computes the length of its
input.~ Solution<#66313#><#66313#>
This discussion raises the question whether there is a difference between
between functions based on structural recursion and those based on
generative recursion. The answer is ``it depends.'' Of course, we could say
that all functions using structural recursion are just special cases of
generative recursion. This ``everything is equal'' attitude, however, is of
no help if we wish to understand the process of designing functions. It
confuses two classes of functions that are designed with different
approaches and that have different consequences. One relies on a systematic
data analysis and not much more; the other requires a deep, often
mathematical, insight into the problem-solving process itself. One
leads programmers to naturally terminating functions; the other requires a
termination argument.
A simple inspection of a function's definition quickly shows whether a
function uses structural or generative recursion. All self-applications of
a structurally recursive function always receive an immediate component of
the current input for further processing. For example, for a
<#66314#><#34027#>cons<#34027#><#66314#>tructed list, the immediate components are the <#66315#><#34028#>first<#34028#><#66315#>
item and the <#66316#><#34029#>rest<#34029#><#66316#> of the list. Hence, if a function consumes a
plain list and its natural recursion does not consume the rest of the list,
its definition is not structural but generative. Or, put positively,
properly recursive algorithms consume newly generated input, which may or
may not contain components of the input. In any case, the new piece of data
represents a different problem than the given one, but still a problem of
the same general class of problems.