<#71153#>;; <#64368#><#21705#>list=?<#21705#> <#21706#>:<#21706#> <#21707#>list-of-numbers<#21707#> <#21708#>list-of-numbers<#21708#> <#21709#><#21709#><#21710#>-;SPMgt;<#21710#><#21711#><#21711#> <#21712#>boolean<#21712#><#64368#><#71153#> <#71154#>;; to determine whether <#64369#><#21713#>a-list<#21713#><#64369#> and <#64370#><#21714#>another-list<#21714#><#64370#> <#71154#> <#21715#>;; contain the same numbers in the same order<#21715#> <#21716#>(define<#21716#> <#21717#>(list=?<#21717#> <#21718#>a-list<#21718#> <#21719#>another-list)<#21719#> <#21720#>...)<#21720#>The purpose statement refines our general claim and reminds us that, for example, shoppers may consider two lists equal if they contain the same items, regardless of the order, but programmers are more specific and include the order in the comparison. The contract and the purpose statement also show that <#64371#><#21724#>list=?<#21724#><#64371#> is a function that processes two complex values, and indeed, it is an interesting case study. Comparing two lists means to look at each item in both lists. This rules out designing <#64372#><#21725#>list=?<#21725#><#64372#> along the lines of <#64373#><#21726#>replace-eol-with<#21726#><#64373#> in section~#sectwoinputscase1#21727>
It has four cells, which implies that we need (at least) four tests and
four <#64378#><#21741#>cond<#21741#><#64378#>-clauses in the template.
Here are five tests:
A <#64477#><#22401#>Sexpr<#22401#><#64477#> is either <#22610#>Unordered Lists<#22610#>:\ On some occasions, we use lists even though the
ordering of the items doesn't play a role. For those cases, it is important
to have functions such as <#64502#><#22611#>contains-same-numbers<#22611#><#64502#> (see
exercise~#exlist5#22612> <#21746#>(list=?<#21746#> <#21747#>empty<#21747#> <#21748#>empty)<#21748#>
<#21749#>=<#21749#> <#21750#>true<#21750#>
<#21758#>(list=?<#21758#> <#21759#>empty<#21759#> <#21760#>(cons<#21760#> <#21761#>1<#21761#> <#21762#>empty))<#21762#>
<#21763#>=<#21763#> <#21764#>false<#21764#>
<#21772#>(list=?<#21772#> <#21773#>(cons<#21773#> <#21774#>1<#21774#> <#21775#>empty)<#21775#> <#21776#>empty)<#21776#>
<#21777#>=<#21777#> <#21778#>false<#21778#>
<#21786#>(list=?<#21786#> <#21787#>(cons<#21787#> <#21788#>1<#21788#> <#21789#>(cons<#21789#> <#21790#>2<#21790#> <#21791#>(cons<#21791#> <#21792#>3<#21792#> <#21793#>empty)))<#21793#>
<#21794#>(cons<#21794#> <#21795#>1<#21795#> <#21796#>(cons<#21796#> <#21797#>2<#21797#> <#21798#>(cons<#21798#> <#21799#>3<#21799#> <#21800#>empty))))<#21800#>
<#21801#>=<#21801#> <#21802#>true<#21802#>
<#21810#>(list=?<#21810#> <#21811#>(cons<#21811#> <#21812#>1<#21812#> <#21813#>(cons<#21813#> <#21814#>2<#21814#> <#21815#>(cons<#21815#> <#21816#>3<#21816#> <#21817#>empty)))<#21817#>
<#21818#>(cons<#21818#> <#21819#>1<#21819#> <#21820#>(cons<#21820#> <#21821#>3<#21821#> <#21822#>empty)))<#21822#>
<#21823#>=<#21823#> <#21824#>false<#21824#>
The second and third show that <#64379#><#21828#>list=?<#21828#><#64379#> must deal with its arguments
in a symmetric fashion. The last two show how <#64380#><#21829#>list=?<#21829#><#64380#> can produce
<#64381#><#21830#>true<#21830#><#64381#> and <#64382#><#21831#>false<#21831#><#64382#>.
Three of the template's four <#64383#><#21832#>cond<#21832#><#64383#>-clauses contain selector
expressions and one contains natural recursions:
<#21837#>(d<#21837#><#21838#>efine<#21838#> <#21839#>(list=?<#21839#> <#21840#>a-list<#21840#> <#21841#>another-list)<#21841#>
<#21842#>(c<#21842#><#21843#>ond<#21843#>
<#21844#>[<#21844#><#21845#>(and<#21845#> <#21846#>(empty?<#21846#> <#21847#>a-list)<#21847#> <#21848#>(empty?<#21848#> <#21849#>another-list))<#21849#> <#21850#>...]<#21850#>
<#21851#>[<#21851#><#21852#>(and<#21852#> <#21853#>(cons?<#21853#> <#21854#>a-list)<#21854#> <#21855#>(empty?<#21855#> <#21856#>another-list))<#21856#>
<#21857#>...<#21857#> <#21858#>(first<#21858#> <#21859#>a-list)<#21859#> <#21860#>...<#21860#> <#21861#>(rest<#21861#> <#21862#>a-list)<#21862#> <#21863#>...]<#21863#>
<#21864#>[<#21864#><#21865#>(and<#21865#> <#21866#>(empty?<#21866#> <#21867#>a-list)<#21867#> <#21868#>(cons?<#21868#> <#21869#>another-list))<#21869#>
<#21870#>...<#21870#> <#21871#>(first<#21871#> <#21872#>another-list)<#21872#> <#21873#>...<#21873#> <#21874#>(rest<#21874#> <#21875#>another-list)<#21875#> <#21876#>...]<#21876#>
<#21877#>[<#21877#><#21878#>(and<#21878#> <#21879#>(cons?<#21879#> <#21880#>a-list)<#21880#> <#21881#>(cons?<#21881#> <#21882#>another-list))<#21882#>
<#21883#>...<#21883#> <#21884#>(first<#21884#> <#21885#>a-list)<#21885#> <#21886#>...<#21886#> <#21887#>(first<#21887#> <#21888#>another-list)<#21888#> <#21889#>...<#21889#>
<#21890#>...<#21890#> <#21891#>(list=?<#21891#> <#21892#>(rest<#21892#> <#21893#>a-list)<#21893#> <#21894#>(rest<#21894#> <#21895#>another-list))<#21895#> <#21896#>...<#21896#>
<#21897#>...<#21897#> <#21898#>(list=?<#21898#> <#21899#>a-list<#21899#> <#21900#>(rest<#21900#> <#21901#>another-list))<#21901#> <#21902#>...<#21902#>
<#21903#>...<#21903#> <#21904#>(list=?<#21904#> <#21905#>(rest<#21905#> <#21906#>a-list)<#21906#> <#21907#>another-list)<#21907#> <#21908#>...]<#21908#><#21909#>))<#21909#>
There are three natural recursions in the fourth clause because we can pair
the two selector expressions and we can pair each parameter with one
selector expression.
From the template to the complete definition is only a small step. Two
lists can only contain the same items if they are both empty or
<#64384#><#21913#>cons<#21913#><#64384#>tructed. This immediately implies <#64385#><#21914#>true<#21914#><#64385#> as the answer
for the first <#64386#><#21915#>clause<#21915#><#64386#> and <#64387#><#21916#>false<#21916#><#64387#> for the next two. In the
last clause, we have two numbers, the first of both lists, and three
natural recursions. We must compare the two numbers. Furthermore,
<#64388#><#21917#>(list=?<#21917#>\ <#21918#>(rest<#21918#>\ <#21919#>a-list)<#21919#>\ <#21920#>(rest<#21920#>\ <#21921#>another-list))<#21921#><#64388#> computes whether the
rests of the two lists are equal. The two lists are equal if, and only if,
both conditions hold, which means we must combine them with an
<#64389#><#21922#>and<#21922#><#64389#>:
<#21927#>(d<#21927#><#21928#>efine<#21928#> <#21929#>(list=?<#21929#> <#21930#>a-list<#21930#> <#21931#>another-list)<#21931#>
<#21932#>(c<#21932#><#21933#>ond<#21933#>
<#21934#>[<#21934#><#21935#>(and<#21935#> <#21936#>(empty?<#21936#> <#21937#>a-list)<#21937#> <#21938#>(empty?<#21938#> <#21939#>another-list))<#21939#> <#21940#>true]<#21940#>
<#21941#>[<#21941#><#21942#>(and<#21942#> <#21943#>(cons?<#21943#> <#21944#>a-list)<#21944#> <#21945#>(empty?<#21945#> <#21946#>another-list))<#21946#> <#21947#>false]<#21947#>
<#21948#>[<#21948#><#21949#>(and<#21949#> <#21950#>(empty?<#21950#> <#21951#>a-list)<#21951#> <#21952#>(cons?<#21952#> <#21953#>another-list))<#21953#> <#21954#>false]<#21954#>
<#21955#>[<#21955#><#21956#>(and<#21956#> <#21957#>(cons?<#21957#> <#21958#>a-list)<#21958#> <#21959#>(cons?<#21959#> <#21960#>another-list))<#21960#>
<#21961#>(and<#21961#> <#21962#>(=<#21962#> <#21963#>(first<#21963#> <#21964#>a-list)<#21964#> <#21965#>(first<#21965#> <#21966#>another-list))<#21966#>
<#21967#>(list=?<#21967#> <#21968#>(rest<#21968#> <#21969#>a-list)<#21969#> <#21970#>(rest<#21970#> <#21971#>another-list)))]<#21971#><#21972#>))<#21972#>
The other two natural recursions play no role.
Let us now take a second look at the connection between the two
parameters. The first development suggests that the second parameter must
have the same shape as the first one, if the two lists are to be equal. Put
differently, we could develop the function based on the structure of the
first parameter and check structure of the other one as needed.
The first parameter is a list of numbers, so we can reuse the template for
list-processing functions:
<#21980#>(d<#21980#><#21981#>efine<#21981#> <#21982#>(list=?<#21982#> <#21983#>a-list<#21983#> <#21984#>another-list)<#21984#>
<#21985#>(c<#21985#><#21986#>ond<#21986#>
<#21987#>[<#21987#><#21988#>(empty?<#21988#> <#21989#>a-list)<#21989#> <#21990#>...]<#21990#>
<#21991#>[<#21991#><#21992#>(cons?<#21992#> <#21993#>a-list)<#21993#>
<#21994#>...<#21994#> <#21995#>(first<#21995#> <#21996#>a-list)<#21996#> <#21997#>...<#21997#> <#21998#>(first<#21998#> <#21999#>another-list)<#21999#> <#22000#>...<#22000#>
<#22001#>...<#22001#> <#22002#>(list=?<#22002#> <#22003#>(rest<#22003#> <#22004#>a-list)<#22004#> <#22005#>(rest<#22005#> <#22006#>another-list))<#22006#> <#22007#>...]<#22007#><#22008#>))<#22008#>
The only difference is that the second clause processes the second
parameter in the same way as the first one. This mimics the development of
<#71155#><#22012#>hours<#22012#><#64390#><#22013#><#22013#><#22014#>-;SPMgt;<#22014#><#22015#><#22015#><#64390#><#22016#>wages<#22016#><#71155#> in section~#sectwoinputscase2#22017>
Given the purpose of the function and the examples, we now simply compare
<#64406#><#22042#>(first<#22042#>\ <#22043#>a-list)<#22043#><#64406#> and <#64407#><#22044#>(first<#22044#>\ <#22045#>another-list)<#22045#><#64407#> and combine the
result with the natural recursion in an <#64408#><#22046#>and<#22046#>-expression<#64408#>:
<#22051#>(and<#22051#> <#22052#>(=<#22052#> <#22053#>(first<#22053#> <#22054#>a-list)<#22054#> <#22055#>(first<#22055#> <#22056#>another-list))<#22056#>
<#22057#>(list=?<#22057#> <#22058#>(rest<#22058#> <#22059#>a-list)<#22059#> <#22060#>(rest<#22060#> <#22061#>another-list)))<#22061#>
While this step appears to be simple and straightforward, the result is an
improper definition. The purpose of spelling out the conditions in a
<#64409#><#22065#>cond<#22065#>-expression<#64409#> is to ensure that all selector expressions are
appropriate. Nothing in the specification of <#64410#><#22066#>list=?<#22066#><#64410#>, however,
suggests that <#64411#><#22067#>another-list<#22067#><#64411#> is <#64412#><#22068#>cons<#22068#><#64412#>tructed if
<#64413#><#22069#>a-list<#22069#><#64413#> is <#64414#><#22070#>cons<#22070#><#64414#>tructed.
We can overcome this problem with an additional condition:
<#22075#>(d<#22075#><#22076#>efine<#22076#> <#22077#>(list=?<#22077#> <#22078#>a-list<#22078#> <#22079#>another-list)<#22079#>
<#22080#>(c<#22080#><#22081#>ond<#22081#>
<#22082#>[<#22082#><#22083#>(empty?<#22083#> <#22084#>a-list)<#22084#> <#22085#>(empty?<#22085#> <#22086#>another-list)]<#22086#>
<#22087#>[<#22087#><#22088#>(cons?<#22088#> <#22089#>a-list)<#22089#>
<#22090#>(and<#22090#> <#22091#>(cons?<#22091#> <#22092#>another-list)<#22092#>
<#22093#>(and<#22093#> <#22094#>(=<#22094#> <#22095#>(first<#22095#> <#22096#>a-list)<#22096#> <#22097#>(first<#22097#> <#22098#>another-list))<#22098#>
<#22099#>(list=?<#22099#> <#22100#>(rest<#22100#> <#22101#>a-list)<#22101#> <#22102#>(rest<#22102#> <#22103#>another-list))))]<#22103#><#22104#>))<#22104#>
The additional condition is <#64415#><#22108#>(cons?<#22108#>\ <#22109#>another-list)<#22109#><#64415#>, which means that
<#64416#><#22110#>list=?<#22110#><#64416#> produces <#64417#><#22111#>false<#22111#><#64417#> if <#64418#><#22112#>(cons?<#22112#>\ <#22113#>a-list)<#22113#><#64418#> is true
and <#64419#><#22114#>(cons?<#22114#>\ <#22115#>another-list)<#22115#><#64419#> is empty. As the examples show, this is
the desired outcome.
In summary, <#64420#><#22116#>list=?<#22116#><#64420#> shows that, on occasion, we can use more than one
design recipe to develop a function. The outcomes are different, though closely
related; indeed, we could prove that the two always produce the same results for
the same inputs. Also, the second development benefited from the first one.
<#22119#>Exercise 17.8.1<#22119#>
<#22154#>(contains-same-numbers<#22154#> <#22155#>(list<#22155#> <#22156#>1<#22156#> <#22157#>2<#22157#> <#22158#>3)<#22158#> <#22159#>(list<#22159#> <#22160#>3<#22160#> <#22161#>2<#22161#> <#22162#>1))<#22162#>
evaluates to <#64432#><#22166#>true<#22166#><#64432#>.~ Solution<#64433#><#64433#>
<#22172#>Exercise 17.8.5<#22172#>
An <#64436#><#22177#>atom<#22177#><#64436#> is either
Develop the function <#64437#><#22181#>list-equal?<#22181#><#64437#>, which consumes two
lists of atoms and determines whether they are
equal.~ Solution<#64438#><#64438#>
A comparison between the two versions of <#64439#><#22189#>list=?<#22189#><#64439#> suggests that the
second one is easier to understand than the first. It says that two compound
values are equal if the second is made from the same constructor and the
components are equal. In general, this idea is a good guide for the development
of other equality functions.
Let's look at an equality function for simple Web pages to confirm this
conjecture:
<#71157#>;; <#64440#><#22194#>web=?<#22194#> <#22195#>:<#22195#> <#22196#>web-page<#22196#> <#22197#>web-page<#22197#> <#22198#><#22198#><#22199#>-;SPMgt;<#22199#><#22200#><#22200#> <#22201#>boolean<#22201#><#64440#><#71157#>
<#71158#>;; to determine whether <#64441#><#22202#>a-wp<#22202#><#64441#> and <#64442#><#22203#>another-wp<#22203#><#64442#> have the same tree shape<#71158#>
<#22204#>;; and contain the same symbols in the same order<#22204#>
<#22205#>(define<#22205#> <#22206#>(web=?<#22206#> <#22207#>a-wp<#22207#> <#22208#>another-wp)<#22208#> <#22209#>...)<#22209#>
Recall the data definition for simple Web pages:
A <#64443#><#22214#>Web page<#22214#><#64443#> (<#64444#><#22215#>WP<#22215#><#64444#>) is either
The data definition has three clauses, which means that if we were to
develop <#64452#><#22230#>web=?<#22230#><#64452#> with the modified design recipe, we would need to study
nine cases. By using the insight gained from the development of <#64453#><#22231#>list=?<#22231#><#64453#>
instead, we can start from the plain web-processing template:
where <#64447#><#22221#>s<#22221#><#64447#> is a symbol and <#64448#><#22222#>wp<#22222#><#64448#> is a Web page; or
where both <#64450#><#22226#>ewp<#22226#><#64450#> and <#64451#><#22227#>wp<#22227#><#64451#> are Web pages. <#22236#>(d<#22236#><#22237#>efine<#22237#> <#22238#>(web=?<#22238#> <#22239#>a-wp<#22239#> <#22240#>another-wp)<#22240#>
<#22241#>(c<#22241#><#22242#>ond<#22242#>
<#22243#>[<#22243#><#22244#>(empty?<#22244#> <#22245#>a-wp)<#22245#> <#22246#>...]<#22246#>
<#22247#>[<#22247#><#22248#>(symbol?<#22248#> <#22249#>(first<#22249#> <#22250#>a-wp))<#22250#>
<#22251#>...<#22251#> <#22252#>(first<#22252#> <#22253#>a-wp)<#22253#> <#22254#>...<#22254#> <#22255#>(first<#22255#> <#22256#>another-wp)<#22256#> <#22257#>...<#22257#>
<#22258#>...<#22258#> <#22259#>(web=?<#22259#> <#22260#>(rest<#22260#> <#22261#>a-wp)<#22261#> <#22262#>(rest<#22262#> <#22263#>another-wp))<#22263#> <#22264#>...]<#22264#>
<#22265#>[<#22265#><#22266#>else<#22266#>
<#22267#>...<#22267#> <#22268#>(web=?<#22268#> <#22269#>(first<#22269#> <#22270#>a-wp)<#22270#> <#22271#>(first<#22271#> <#22272#>another-wp))<#22272#> <#22273#>...<#22273#>
<#22274#>...<#22274#> <#22275#>(web=?<#22275#> <#22276#>(rest<#22276#> <#22277#>a-wp)<#22277#> <#22278#>(rest<#22278#> <#22279#>another-wp))<#22279#> <#22280#>...]<#22280#><#22281#>))<#22281#>
In the second <#64454#><#22285#>cond<#22285#><#64454#>-clause, we follow the example of
<#71159#><#22286#>hours<#22286#><#64455#><#22287#><#22287#><#22288#>-;SPMgt;<#22288#><#22289#><#22289#><#64455#><#22290#>wages<#22290#><#71159#> and <#64456#><#22291#>list=?<#22291#><#64456#> again. That is, we say that
<#64457#><#22292#>another-wp<#22292#><#64457#> must have the same shape as <#64458#><#22293#>a-wp<#22293#><#64458#> if it is to
be equal and process the two pages in an analogous manner. The reasoning
for the third clause is similar.
As we refine this template into a full definition now, we must again add
conditions on <#64459#><#22294#>another-wp<#22294#><#64459#> to ensure that the selector expressions
are justified:
<#22299#>(d<#22299#><#22300#>efine<#22300#> <#22301#>(web=?<#22301#> <#22302#>a-wp<#22302#> <#22303#>another-wp)<#22303#>
<#22304#>(c<#22304#><#22305#>ond<#22305#>
<#22306#>[<#22306#><#22307#>(empty?<#22307#> <#22308#>a-wp)<#22308#> <#22309#>(empty?<#22309#> <#22310#>another-wp)]<#22310#>
<#22311#>[<#22311#><#22312#>(symbol?<#22312#> <#22313#>(first<#22313#> <#22314#>a-wp))<#22314#>
<#22315#>(and<#22315#> <#22316#>(and<#22316#> <#22317#>(cons?<#22317#> <#22318#>another-wp)<#22318#> <#22319#>(symbol?<#22319#> <#22320#>(first<#22320#> <#22321#>another-wp)))<#22321#>
<#22322#>(and<#22322#> <#22323#>(symbol=?<#22323#> <#22324#>(first<#22324#> <#22325#>a-wp)<#22325#> <#22326#>(first<#22326#> <#22327#>another-wp))<#22327#>
<#22328#>(web=?<#22328#> <#22329#>(rest<#22329#> <#22330#>a-wp)<#22330#> <#22331#>(rest<#22331#> <#22332#>another-wp))))]<#22332#>
<#22333#>[<#22333#><#22334#>else<#22334#>
<#22335#>(and<#22335#> <#22336#>(and<#22336#> <#22337#>(cons?<#22337#> <#22338#>another-wp)<#22338#> <#22339#>(list?<#22339#> <#22340#>(first<#22340#> <#22341#>another-wp)))<#22341#>
<#22342#>(and<#22342#> <#22343#>(web=?<#22343#> <#22344#>(first<#22344#> <#22345#>a-wp)<#22345#> <#22346#>(first<#22346#> <#22347#>another-wp))<#22347#>
<#22348#>(web=?<#22348#> <#22349#>(rest<#22349#> <#22350#>a-wp)<#22350#> <#22351#>(rest<#22351#> <#22352#>another-wp))))]<#22352#><#22353#>))<#22353#>
In particular, we must ensure in the second and third clause that
<#64460#><#22357#>another-wp<#22357#><#64460#> is a <#64461#><#22358#>cons<#22358#><#64461#>tructed list and that the first item
is a symbol or a list, respectively. Otherwise the function is analogous to
<#64462#><#22359#>list=?<#22359#><#64462#> and works in the same way.
<#22362#>Exercise 17.8.6<#22362#>
A <#64470#><#22390#>Slist<#22390#><#64470#> is either
Develop the function <#64479#><#22406#>Slist=?<#22406#><#64479#>, which consumes two
<#64480#><#22407#>Slists<#22407#><#64480#> and determines whether they are equal. Like lists of
numbers, two Slists are equal is they contain the same item at analogous
positions.~ Solution<#64481#><#64481#>
Now that we have explored the idea of equality of values, we can return to
the original motivation of the section: testing functions. Suppose we wish
to test <#71160#><#22415#>hours<#22415#><#64482#><#22416#><#22416#><#22417#>-;SPMgt;<#22417#><#22418#><#22418#><#64482#><#22419#>wages<#22419#><#71160#> from section~#sectwoinputscase2#22420> <#22425#>(<#22425#><#22426#>hours<#22426#><#64483#><#22427#><#22427#><#22428#>-;SPMgt;<#22428#><#22429#><#22429#><#64483#><#22430#>wages<#22430#> <#22431#>(cons<#22431#> <#22432#>5.65<#22432#> <#22433#>(cons<#22433#> <#22434#>8.75<#22434#> <#22435#>empty))<#22435#>
<#22436#>(cons<#22436#> <#22437#>40<#22437#> <#22438#>(cons<#22438#> <#22439#>30<#22439#> <#22440#>empty)))<#22440#>
<#22441#>=<#22441#> <#22442#>(cons<#22442#> <#22443#>226.0<#22443#> <#22444#>(cons<#22444#> <#22445#>262.5<#22445#> <#22446#>empty))<#22446#>
If we just type in the application into <#22450#>Interactions<#22450#> window or add
it to the bottom of the <#22451#>Definitions<#22451#> window, we must compare the
result and the predicted value by inspection. For short lists, like the ones
above, this is feasible; for long lists, deep Web pages, or other large
compound data, manual inspection is error-prone.
Using equality functions like <#64484#><#22452#>list=?<#22452#><#64484#>, we can greatly reduce the need
for manual inspection of test results. In our running example, we can add the
expression
<#22457#>(l<#22457#><#22458#>ist=?<#22458#>
<#22459#>(<#22459#><#22460#>hours<#22460#><#64485#><#22461#><#22461#><#22462#>-;SPMgt;<#22462#><#22463#><#22463#><#64485#><#22464#>wages<#22464#> <#22465#>(cons<#22465#> <#22466#>5.65<#22466#> <#22467#>(cons<#22467#> <#22468#>8.75<#22468#> <#22469#>empty))<#22469#>
<#22470#>(cons<#22470#> <#22471#>40<#22471#> <#22472#>(cons<#22472#> <#22473#>30<#22473#> <#22474#>empty)))<#22474#>
<#22475#>(cons<#22475#> <#22476#>226.0<#22476#> <#22477#>(cons<#22477#> <#22478#>262.5<#22478#> <#22479#>empty)))<#22479#>
to the bottom of the <#22483#>Definitions<#22483#> window. When we click the
<#22484#>Execute<#22484#> button now, we just need to make sure that all test cases
produce <#64486#><#22485#>true<#22485#><#64486#> as their results are displayed in the
<#22486#>Interactions<#22486#> window.
<#72226#>;; <#71161#><#22491#>test-hours<#22491#><#64487#><#22492#><#22492#><#22493#>-;SPMgt;<#22493#><#22494#><#22494#><#64487#><#22495#>wages<#22495#> <#22496#>:<#22496#> <#22497#>list-of-numbers<#22497#> <#22498#>list-of-numbers<#22498#> <#22499#>list-of-numbers<#22499#> <#22500#><#22500#><#22501#>-;SPMgt;<#22501#><#22502#><#22502#> <#22503#>test-result<#22503#><#71161#><#72226#>
<#72227#>;; to test <#71162#><#22504#>hours<#22504#><#64488#><#22505#><#22505#><#22506#>-;SPMgt;<#22506#><#22507#><#22507#><#64488#><#22508#>wages<#22508#><#71162#><#72227#>
<#22509#>(d<#22509#><#22510#>efine<#22510#> <#22511#>(<#22511#><#22512#>test-hours<#22512#><#64489#><#22513#><#22513#><#22514#>-;SPMgt;<#22514#><#22515#><#22515#><#64489#><#22516#>wages<#22516#> <#22517#>a-list<#22517#> <#22518#>another-list<#22518#> <#22519#>expected-result)<#22519#>
<#22520#>(c<#22520#><#22521#>ond<#22521#>
<#22522#>[<#22522#><#22523#>(list=?<#22523#> <#22524#>(<#22524#><#22525#>hours<#22525#><#64490#><#22526#><#22526#><#22527#>-;SPMgt;<#22527#><#22528#><#22528#><#64490#><#22529#>wages<#22529#> <#22530#>a-list<#22530#> <#22531#>another-list)<#22531#> <#22532#>expected-result)<#22532#>
<#22533#>true]<#22533#>
<#22534#>[<#22534#><#22535#>else<#22535#>
<#22536#>(list<#22536#> <#22537#>``bad<#22537#> <#22538#>test<#22538#> <#22539#>result:''<#22539#> <#22540#>a-list<#22540#> <#22541#>another-list<#22541#> <#22542#>expected-result)]<#22542#><#22543#>))<#22543#>
<#22547#>Figure: A test function<#22547#>
Indeed, we can go even further. We can write a test function like the one
in figure~#figtestfunction#22549><#22564#>(<#22564#><#22565#>test-hours<#22565#><#64495#><#22566#><#22566#><#22567#>-;SPMgt;<#22567#><#22568#><#22568#><#64495#><#22569#>wages<#22569#>
<#22570#>(cons<#22570#> <#22571#>5.65<#22571#> <#22572#>(cons<#22572#> <#22573#>8.75<#22573#> <#22574#>empty))<#22574#>
<#22575#>(cons<#22575#> <#22576#>40<#22576#> <#22577#>(cons<#22577#> <#22578#>30<#22578#> <#22579#>empty))<#22579#>
<#22580#>(cons<#22580#> <#22581#>226.0<#22581#> <#22582#>(cons<#22582#> <#22583#>262.5<#22583#> <#22584#>empty)))<#22584#>
If something goes wrong with the test cases, the four-item list will stand
out and specify precisely which test case failed.
The designers of Scheme anticipated the need of a general equality
procedure and provide
<#71164#>;; <#64496#><#22592#>equal?<#22592#> <#22593#>:<#22593#> <#22594#>any-value<#22594#> <#22595#>any-value<#22595#> <#22596#><#22596#><#22597#>-;SPMgt;<#22597#><#22598#><#22598#> <#22599#>boolean<#22599#><#64496#><#71164#>
<#22600#>;; to determine whether two values are structurally equivalent <#22600#>
<#22601#>;; and contain the same atomic values in analogous positions <#22601#>
When <#64497#><#22605#>equal?<#22605#><#64497#> is applied to two lists, it compares them in the same
manner as <#64498#><#22606#>list=?<#22606#><#64498#>; when it encounters a pair of structures, it
compares their corresponding fields, if they are the same kind of
structures; and when it consumes a pair of atomic values, it compares them
with <#64499#><#22607#>=<#22607#><#64499#>, <#64500#><#22608#>symbol=?<#22608#><#64500#>, or <#64501#><#22609#>boolean=?<#22609#><#64501#>, whatever is
appropriate.
<#22617#>Exercise 17.8.10<#22617#>