Newspapers often contain exercises that ask readers to find all possible words
made up from some letters. One way to play this game is to form all possible
arrangements of the letters in a systematic manner and to see which
arrangements are dictionary words. Suppose the letters ``a'', ``d'', ``e'',
and ``r'' are given. There are twenty-four possible arrangements of these
letters:
#tabular14871#
The three legitimate words in this list are ``read'', ``dear'', and
``dare.''
The systematic enumeration of all possible arrangements is clearly a task
for a computer program. It consumes a word and produces a list of the
word's letter-by-letter rearrangements.
A simple representation of a word is a list of symbols. Each item in the
input represents a letter: <#63134#><#14890#>'<#14890#><#14891#>a<#14891#><#63134#>, <#63135#><#14892#>'<#14892#><#14893#>b<#14893#><#63135#>, ..., <#63136#><#14894#>'<#14894#><#14895#>z<#14895#><#63136#>.
Here is the data definition for the class of words:
A <#63137#><#14897#>word<#14897#><#63137#> is either
- <#63138#><#14899#>empty<#14899#><#63138#>, or
- <#63139#><#14900#>(cons<#14900#>\ <#14901#>a<#14901#>\ <#14902#>w)<#14902#><#63139#> where <#63140#><#14903#>a<#14903#><#63140#> is a symbol (<#63141#><#14904#>'<#14904#><#14905#>a<#14905#><#63141#>, <#63142#><#14906#>'<#14906#><#14907#>b<#14907#><#63142#>, ..., <#63143#><#14908#>'<#14908#><#14909#>z<#14909#><#63143#>) and <#63144#><#14910#>w<#14910#><#63144#> is a word.
<#14915#>Exercise 12.4.1<#14915#>
Formulate the data definition for lists of words. Systematically make up
examples of words and lists of words.~ Solution<#63145#><#63145#>
Let us call the function <#63146#><#14922#>arrangements<#14922#><#63146#>. Its template is that of a list-processing
function:
<#71040#>;; <#63148#><#14928#>arrangements<#14928#> <#14929#>:<#14929#> <#14930#>word<#14930#> <#14931#><#14931#><#14932#>-;SPMgt;<#14932#><#14933#><#14933#> <#14934#>list-of-words<#14934#><#63148#><#71040#>
<#71041#>;; to create a list of all re-arrangements of the letters in <#63149#><#14935#>a-word<#14935#><#63149#><#71041#>
<#14936#>(d<#14936#><#14937#>efine<#14937#> <#14938#>(arrangements<#14938#> <#14939#>a-word)<#14939#>
<#14940#>(c<#14940#><#14941#>ond<#14941#>
<#14942#>[<#14942#><#14943#>(empty?<#14943#> <#14944#>a-word)<#14944#> <#14945#>...]<#14945#>
<#14946#>[<#14946#><#14947#>else<#14947#> <#14948#>...<#14948#> <#14949#>(first<#14949#> <#14950#>a-word)<#14950#> <#14951#>...<#14951#> <#14952#>(arrangements<#14952#> <#14953#>(rest<#14953#> <#14954#>a-word))<#14954#> <#14955#>...]<#14955#><#14956#>))<#14956#>
Given the contract, the supporting data definitions, and the examples, we
can now look at each <#63150#><#14960#>cond<#14960#><#63150#>-line in the template:
- If the input is <#63151#><#14962#>empty<#14962#><#63151#>, there is only one possible re-arrangement of
the input: the <#63152#><#14963#>empty<#14963#><#63152#> word. Hence, the result is <#63153#><#14964#>(cons<#14964#><#14965#> <#14965#><#14966#>empty<#14966#>\ <#14967#>empty)<#14967#><#63153#>, the list that contains the empty list as the only item.
- Otherwise there is a first letter in the word, and <#63154#><#14968#>(first<#14968#><#14969#> <#14969#><#14970#>a-word)<#14970#><#63154#> is that letter and the recursion produces the list of all possible
re-arrangements for the rest of the word. For example, if the list is
<#14975#>(cons<#14975#> <#14976#>'<#14976#><#14977#>d<#14977#> <#14978#>(cons<#14978#> <#14979#>'<#14979#><#14980#>e<#14980#> <#14981#>(cons<#14981#> <#14982#>'<#14982#><#14983#>r<#14983#> <#14984#>empty)))<#14984#>
then the recursion is <#63155#><#14988#>(arrangements<#14988#>\ <#14989#>(cons<#14989#>\ <#14990#>'<#14990#><#14991#>e<#14991#>\ <#14992#>(cons<#14992#>\ <#14993#>'<#14993#><#14994#>r<#14994#><#14995#> <#14995#><#14996#>empty)))<#14996#><#63155#>. It will produce the result
<#15001#>(c<#15001#><#15002#>ons<#15002#> <#15003#>(cons<#15003#> <#15004#>'<#15004#><#15005#>e<#15005#> <#15006#>(cons<#15006#> <#15007#>'<#15007#><#15008#>r<#15008#> <#15009#>empty))<#15009#>
<#15010#>(c<#15010#><#15011#>ons<#15011#> <#15012#>(cons<#15012#> <#15013#>'<#15013#><#15014#>r<#15014#> <#15015#>(cons<#15015#> <#15016#>'<#15016#><#15017#>e<#15017#> <#15018#>empty))<#15018#>
<#15019#>empty))<#15019#>
To obtain all possible re-arrangements for the entire list, we
must now insert the first item, <#63156#><#15023#>'<#15023#><#15024#>d<#15024#><#63156#> in our case, into all of these
words between all possible letters and at the beginning and end.
The task of inserting a letter into many different words requires
processing an arbitrarily large list. So, we need another function, call it
<#63157#><#15026#>insert-everywhere/in-all-words<#15026#><#63157#>, to complete the definition of
<#63158#><#15027#>arrangements<#15027#><#63158#>:
<#15032#>(d<#15032#><#15033#>efine<#15033#> <#15034#>(arrangements<#15034#> <#15035#>a-word)<#15035#>
<#15036#>(c<#15036#><#15037#>ond<#15037#>
<#15038#>[<#15038#><#15039#>(empty?<#15039#> <#15040#>a-word)<#15040#> <#15041#>(cons<#15041#> <#15042#>empty<#15042#> <#15043#>empty)]<#15043#>
<#15044#>[<#15044#><#15045#>else<#15045#> <#15046#>(i<#15046#><#15047#>nsert-everywhere/in-all-words<#15047#> <#15048#>(first<#15048#> <#15049#>a-word)<#15049#>
<#15050#>(arrangements<#15050#> <#15051#>(rest<#15051#> <#15052#>a-word)))]<#15052#><#15053#>))<#15053#>
<#15057#>Exercise 12.4.2<#15057#>
Develop the function <#63159#><#15059#>insert-everywhere/in-all-words<#15059#><#63159#>. It consumes a
symbol and a list of words. The result is a list of words like its second
argument, but with the first argument inserted between all letters and at
the beginning and the end of all words of the second argument.
<#15060#>Hint:<#15060#> \ Re-consider the example from above. We stopped and decided that we
needed to insert <#63160#><#15061#>'<#15061#><#15062#>d<#15062#><#63160#> into the words <#63161#><#15063#>(cons<#15063#>\ <#15064#>'<#15064#><#15065#>e<#15065#>\ <#15066#>(cons<#15066#>\ <#15067#>'<#15067#><#15068#>r<#15068#><#15069#> <#15069#><#15070#>empty))<#15070#><#63161#> and <#63162#><#15071#>(cons<#15071#>\ <#15072#>'<#15072#><#15073#>r<#15073#>\ <#15074#>(cons<#15074#>\ <#15075#>'<#15075#><#15076#>e<#15076#>\ <#15077#>empty))<#15077#><#63162#>. The following is therefore
a natural candidate
<#15082#>(i<#15082#><#15083#>nsert-everywhere/in-all-words<#15083#> <#15084#>'<#15084#><#15085#>d<#15085#>
<#15086#>(c<#15086#><#15087#>ons<#15087#> <#15088#>(cons<#15088#> <#15089#>'<#15089#><#15090#>e<#15090#> <#15091#>(cons<#15091#> <#15092#>'<#15092#><#15093#>r<#15093#> <#15094#>empty))<#15094#>
<#15095#>(c<#15095#><#15096#>ons<#15096#> <#15097#>(cons<#15097#> <#15098#>'<#15098#><#15099#>r<#15099#> <#15100#>(cons<#15100#> <#15101#>'<#15101#><#15102#>e<#15102#> <#15103#>empty))<#15103#>
<#15104#>empty)))<#15104#>
for the ``function examples'' step. Keep in mind that the second input
corresponds to the sequence of (partial) words ``er'' and
``re''. Solution<#63163#><#63163#>