Errors in Advanced Scheme

The extension of our language with functions as values not only introduces new powers for the programmer but also new possibilities for errors. Recall that there are three kinds of errors: syntax errors, run-time (or semantics) errors, and logical errors. <#50131#>Advanced Student<#50131#> Scheme turns a class of syntactic errors of <#50132#>Beginning Student<#50132#> Scheme into run-time errors. It also introduces a new form of logical error. Consider the following program:
<#71917#>;; <#69029#><#50137#>how-many-in-list<#50137#> <#50138#>:<#50138#> <#50139#>(listof<#50139#> <#50140#>X)<#50140#> <#50141#><#50141#><#50142#>-;SPMgt;<#50142#><#50143#><#50143#> <#50144#>N<#50144#><#69029#><#71917#>
<#71918#>;; to count how many items <#69030#><#50145#>alist<#50145#><#69030#> contains <#71918#> 
<#50146#>(d<#50146#><#50147#>efine<#50147#> <#50148#>(how-many-in-list<#50148#> <#50149#>alist)<#50149#> 
  <#50150#>(c<#50150#><#50151#>ond<#50151#> 
    <#50152#>[<#50152#><#50153#>empty?<#50153#> <#50154#>(alist)]<#50154#> 
    <#50155#>[<#50155#><#50156#>else<#50156#> <#50157#>(+<#50157#> <#50158#>(how-many-in-list<#50158#> <#50159#>(rest<#50159#> <#50160#>alist))<#50160#> <#50161#>1)]<#50161#><#50162#>))<#50162#> 
In <#50166#>Beginning Student<#50166#> or <#50167#>Intermediate Student<#50167#> Scheme, DrScheme would have signaled a syntax error because <#69031#><#50168#>alist<#50168#><#69031#> is the parameter to a function but is also used as a function. Because functions are values in <#50169#>Advanced Student<#50169#> Scheme, DrScheme must now accept this function definition as syntactially correct. When the function is applied to <#69032#><#50170#>empty<#50170#><#69032#> or any other list value, however, DrScheme soon applies <#69033#><#50171#>empty<#50171#><#69033#> to no arguments, which is a run-time error. After all, lists are not functions. DrScheme signals any attempt to apply a non-function immediately with an error message and stops the evaluation. The second form of error is logical. That is, a program that suffers from this form of error doesn't produce a syntax or a run-time error message. Instead, it produces wrong answers. Take a look at the following two definitions:
<#50176#>(d<#50176#><#50177#>efine<#50177#> <#50178#>flip1<#50178#>
  <#50179#>(l<#50179#><#50180#>ocal<#50180#> <#50181#>((define<#50181#> <#50182#>state<#50182#> <#50183#>1))<#50183#> 
    <#50184#>(l<#50184#><#50185#>ambda<#50185#> <#50186#>()<#50186#> 
      <#50187#>(b<#50187#><#50188#>egin<#50188#> 
        <#50189#>(set!<#50189#> <#50190#>state<#50190#> <#50191#>(-<#50191#> <#50192#>1<#50192#> <#50193#>state))<#50193#> 
        <#50194#>state))))<#50194#> 
<#50200#>(d<#50200#><#50201#>efine<#50201#> <#50202#>flip2<#50202#>
  <#50203#>(l<#50203#><#50204#>ambda<#50204#> <#50205#>()<#50205#> 
    <#50206#>(l<#50206#><#50207#>ocal<#50207#> <#50208#>((define<#50208#> <#50209#>state<#50209#> <#50210#>1))<#50210#> 
      <#50211#>(b<#50211#><#50212#>egin<#50212#> 
        <#50213#>(set!<#50213#> <#50214#>state<#50214#> <#50215#>(-<#50215#> <#50216#>1<#50216#> <#50217#>state))<#50217#> 
        <#50218#>state))))<#50218#> 
They differ in the order of two lines. One introduces a <#69034#><#50222#>local<#50222#><#69034#> definition whose body evaluates to a function. The other defines a function whose body contains a <#50223#>local<#50223#>-expression. According to our rules, the definition on the left rewrites to
<#50228#>(define<#50228#> <#50229#>state1<#50229#> <#50230#>1)<#50230#>

<#50231#>(d<#50231#><#50232#>efine<#50232#> <#50233#>flip1<#50233#> 
  <#50234#>(l<#50234#><#50235#>ambda<#50235#> <#50236#>()<#50236#> 
    <#50237#>(b<#50237#><#50238#>egin<#50238#> 
      <#50239#>(set!<#50239#> <#50240#>state1<#50240#> <#50241#>(-<#50241#> <#50242#>1<#50242#> <#50243#>state1))<#50243#> 
      <#50244#>state1)))<#50244#> 
<#50250#>(d<#50250#><#50251#>efine<#50251#> <#50252#>flip2<#50252#>
  <#50253#>(l<#50253#><#50254#>ambda<#50254#> <#50255#>()<#50255#> 
    <#50256#>(l<#50256#><#50257#>ocal<#50257#> <#50258#>((define<#50258#> <#50259#>state<#50259#> <#50260#>1))<#50260#> 
      <#50261#>(b<#50261#><#50262#>egin<#50262#> 
        <#50263#>(set!<#50263#> <#50264#>state<#50264#> <#50265#>(-<#50265#> <#50266#>1<#50266#> <#50267#>state))<#50267#> 
        <#50268#>state))))<#50268#> 

The one on the right already associates a name with a function. Let us now see how the two functions have radically different behaviors. To do so, we evaluate the expressions
<#50276#>(and<#50276#> <#50277#>(=<#50277#> <#50278#>(flip1)<#50278#> <#50279#>0)<#50279#>
     <#50280#>(=<#50280#> <#50281#>(flip1)<#50281#> <#50282#>1)<#50282#> 
     <#50283#>(=<#50283#> <#50284#>(flip1)<#50284#> <#50285#>0))<#50285#> 
<#50291#>(and<#50291#> <#50292#>(=<#50292#> <#50293#>(flip2)<#50293#> <#50294#>0)<#50294#>
     <#50295#>(=<#50295#> <#50296#>(flip2)<#50296#> <#50297#>1)<#50297#> 
     <#50298#>(=<#50298#> <#50299#>(flip2)<#50299#> <#50300#>0))<#50300#> 
in the context of the respective definitions. Here are the first four steps of the evaluation for the left-hand expression:
  <#50308#>(define<#50308#> <#50309#>state1<#50309#> <#50310#>1)<#50310#>
  <#50311#>(and<#50311#> <#50312#>(=<#50312#> <#50313#>(flip1)<#50313#> <#50314#>0)<#50314#> 
       <#50315#>(=<#50315#> <#50316#>(flip1)<#50316#> <#50317#>1)<#50317#> 
       <#50318#>(=<#50318#> <#50319#>(flip1)<#50319#> <#50320#>0))<#50320#> 
<#50321#>=<#50321#> <#50322#>(define<#50322#> <#50323#>state1<#50323#> <#50324#>1)<#50324#> 
  <#50325#>(and<#50325#> <#50326#>(=<#50326#> <#50327#>(b<#50327#><#50328#>egin<#50328#> 
            <#50329#>(set!<#50329#> <#50330#>state1<#50330#> <#50331#>(-<#50331#> <#50332#>1<#50332#> <#50333#>state1))<#50333#> 
            <#50334#>state1)<#50334#> 
          <#50335#>0)<#50335#> 
       <#50336#>(=<#50336#> <#50337#>(flip1)<#50337#> <#50338#>1)<#50338#> 
       <#50339#>(=<#50339#> <#50340#>(flip1)<#50340#> <#50341#>0))<#50341#> 
<#50342#>=<#50342#> <#50343#>(define<#50343#> <#50344#>state1<#50344#> <#50345#>1)<#50345#> 
  <#50346#>(and<#50346#> <#50347#>(=<#50347#> <#50348#>(b<#50348#><#50349#>egin<#50349#> 
            <#50350#>(set!<#50350#> <#50351#>state1<#50351#> <#50352#>0)<#50352#> 
            <#50353#>state1)<#50353#> 
          <#50354#>0)<#50354#> 
       <#50355#>(=<#50355#> <#50356#>(flip1)<#50356#> <#50357#>1)<#50357#> 
       <#50358#>(=<#50358#> <#50359#>(flip1)<#50359#> <#50360#>0))<#50360#> 
<#50361#>=<#50361#> <#50362#>(define<#50362#> <#50363#>state1<#50363#> <#50364#>0)<#50364#> 
  <#50365#>(and<#50365#> <#50366#>(=<#50366#> <#50367#>(b<#50367#><#50368#>egin<#50368#> 
            <#50369#>(<#50369#><#50370#>void<#50370#><#50371#>)<#50371#> 
            <#50372#>state1)<#50372#> 
          <#50373#>0)<#50373#> 
       <#50374#>(=<#50374#> <#50375#>(flip1)<#50375#> <#50376#>1)<#50376#> 
       <#50377#>(=<#50377#> <#50378#>(flip1)<#50378#> <#50379#>0))<#50379#> 
<#50380#>=<#50380#> <#50381#>(define<#50381#> <#50382#>state1<#50382#> <#50383#>0)<#50383#> 
  <#50384#>(and<#50384#> <#50385#>(=<#50385#> <#50386#>0<#50386#> <#50387#>0)<#50387#> 
       <#50388#>(=<#50388#> <#50389#>(flip1)<#50389#> <#50390#>1)<#50390#> 
       <#50391#>(=<#50391#> <#50392#>(flip1)<#50392#> <#50393#>0))<#50393#> 
The relevant definition context is the definition of <#69035#><#50397#>state1<#50397#><#69035#>, which we see changing from <#69036#><#50398#>1<#50398#><#69036#> to <#69037#><#50399#>0<#50399#><#69037#> during the third step. From this point, it is not difficult to validate that the expression produces <#69038#><#50400#>true<#50400#><#69038#> and that <#69039#><#50401#>state1<#50401#><#69039#> ends up being <#69040#><#50402#>0<#50402#><#69040#>. Compare this with the first three steps in the evaluation of the right-hand expression:
  <#50407#>(and<#50407#> <#50408#>(=<#50408#> <#50409#>(flip2)<#50409#> <#50410#>0)<#50410#>
       <#50411#>(=<#50411#> <#50412#>(flip2)<#50412#> <#50413#>1)<#50413#> 
       <#50414#>(=<#50414#> <#50415#>(flip2)<#50415#> <#50416#>0))<#50416#> 
<#50417#>=<#50417#> <#50418#>(and<#50418#> <#50419#>(=<#50419#> <#50420#>(l<#50420#><#50421#>ocal<#50421#> <#50422#>((define<#50422#> <#50423#>state<#50423#> <#50424#>1))<#50424#> 
            <#50425#>(b<#50425#><#50426#>egin<#50426#> 
              <#50427#>(set!<#50427#> <#50428#>state<#50428#> <#50429#>(-<#50429#> <#50430#>1<#50430#> <#50431#>state))<#50431#> 
              <#50432#>state))<#50432#> 
          <#50433#>0)<#50433#> 
       <#50434#>(=<#50434#> <#50435#>(flip2)<#50435#> <#50436#>1)<#50436#> 
       <#50437#>(=<#50437#> <#50438#>(flip2)<#50438#> <#50439#>0))<#50439#> 
<#50440#>=<#50440#> <#50441#>(define<#50441#> <#50442#>state1<#50442#> <#50443#>1)<#50443#> 
  <#50444#>(and<#50444#> <#50445#>(=<#50445#> <#50446#>(b<#50446#><#50447#>egin<#50447#> 
            <#50448#>(set!<#50448#> <#50449#>state1<#50449#> <#50450#>(-<#50450#> <#50451#>1<#50451#> <#50452#>state1))<#50452#> 
            <#50453#>state1)<#50453#> 
          <#50454#>0)<#50454#> 
       <#50455#>(=<#50455#> <#50456#>(flip2)<#50456#> <#50457#>1)<#50457#> 
       <#50458#>(=<#50458#> <#50459#>(flip2)<#50459#> <#50460#>0))<#50460#> 
<#50461#>=<#50461#> <#50462#>(define<#50462#> <#50463#>state1<#50463#> <#50464#>0)<#50464#> 
  <#50465#>(and<#50465#> <#50466#>(=<#50466#> <#50467#>0<#50467#> <#50468#>0)<#50468#> 
       <#50469#>(=<#50469#> <#50470#>(flip2)<#50470#> <#50471#>1)<#50471#> 
       <#50472#>(=<#50472#> <#50473#>(flip2)<#50473#> <#50474#>0))<#50474#> 
The only definition that matters here is the one for <#69041#><#50478#>flip2<#50478#><#69041#>. Superficially, the two evaluations are alike. But a closer look shows that the second one differs from the first in crucial way. It creates the definition for <#69042#><#50479#>state1<#50479#><#69042#> while the first evaluation started with such a definition. Here is the continuation of the second evaluation:
  <#50484#>...<#50484#> 
<#50485#>=<#50485#> <#50486#>(define<#50486#> <#50487#>state1<#50487#> <#50488#>0)<#50488#> 
  <#50489#>(and<#50489#> <#50490#>true<#50490#> 
       <#50491#>(=<#50491#> <#50492#>(l<#50492#><#50493#>ocal<#50493#> <#50494#>((define<#50494#> <#50495#>state<#50495#> <#50496#>1))<#50496#> 
            <#50497#>(b<#50497#><#50498#>egin<#50498#> 
              <#50499#>(set!<#50499#> <#50500#>state<#50500#> <#50501#>(-<#50501#> <#50502#>1<#50502#> <#50503#>state))<#50503#> 
              <#50504#>state))<#50504#> 
          <#50505#>1)<#50505#> 
       <#50506#>(=<#50506#> <#50507#>(flip2)<#50507#> <#50508#>0))<#50508#> 
<#50509#>=<#50509#> <#50510#>(define<#50510#> <#50511#>state1<#50511#> <#50512#>0)<#50512#> 
  <#50513#>(define<#50513#> <#50514#>state2<#50514#> <#50515#>1)<#50515#> 
  <#50516#>(and<#50516#> <#50517#>true<#50517#> 
       <#50518#>(=<#50518#> <#50519#>(b<#50519#><#50520#>egin<#50520#> 
            <#50521#>(set!<#50521#> <#50522#>state2<#50522#> <#50523#>(-<#50523#> <#50524#>1<#50524#> <#50525#>state2))<#50525#> 
            <#50526#>state2)<#50526#> 
          <#50527#>1)<#50527#> 
       <#50528#>(=<#50528#> <#50529#>(flip2)<#50529#> <#50530#>0))<#50530#> 
<#50531#>=<#50531#> <#50532#>(define<#50532#> <#50533#>state1<#50533#> <#50534#>0)<#50534#> 
  <#50535#>(define<#50535#> <#50536#>state2<#50536#> <#50537#>0)<#50537#> 
  <#50538#>(and<#50538#> <#50539#>true<#50539#> 
       <#50540#>(=<#50540#> <#50541#>(b<#50541#><#50542#>egin<#50542#> 
            <#50543#>(<#50543#><#50544#>void<#50544#><#50545#>)<#50545#> 
            <#50546#>state2)<#50546#> 
          <#50547#>1)<#50547#> 
       <#50548#>(=<#50548#> <#50549#>(flip2)<#50549#> <#50550#>0))<#50550#> 
<#50551#>=<#50551#> <#50552#>(define<#50552#> <#50553#>state1<#50553#> <#50554#>0)<#50554#> 
  <#50555#>(define<#50555#> <#50556#>state2<#50556#> <#50557#>0)<#50557#> 
  <#50558#>(and<#50558#> <#50559#>true<#50559#> 
       <#50560#>(=<#50560#> <#50561#>0<#50561#> <#50562#>1)<#50562#> 
       <#50563#>(=<#50563#> <#50564#>(flip2)<#50564#> <#50565#>0))<#50565#> 
It shows that <#69043#><#50569#>flip2<#50569#><#69043#> creates a new definition every time it is applied and that it always produces <#69044#><#50570#>0<#50570#><#69044#>. Contrary to its name, it does not flip the value of <#69045#><#50571#>state<#50571#><#69045#> upon every application. As a result, the evaluation ends now with two new top-level definitions and the value <#69046#><#50572#>false<#50572#><#69046#>. The general moral is that a function defined in a <#50573#>local<#50573#>-expression\ is different from a function whose body contains a <#50574#>local<#50574#>-expression. The first ensures that some definitions are only accessible to a function. The definitions exists once and only once for this function. In contrast, the second creates new top-level the evaluation of the function body. In the next part of the book, we exploit both ideas to create new kinds of programs.