Intensional Equality

Consider the following toy program:
<#57077#>(define<#57077#> <#57078#>a<#57078#> <#57079#>(make-posn<#57079#> <#57080#>12<#57080#> <#57081#>1))<#57081#>
<#57082#>(define<#57082#> <#57083#>b<#57083#> <#57084#>(make-posn<#57084#> <#57085#>12<#57085#> <#57086#>1))<#57086#> 
<#57087#>(b<#57087#><#57088#>egin<#57088#> 
  <#57089#>(set-posn-x!<#57089#> <#57090#>a<#57090#> <#57091#>1)<#57091#> 
  <#57092#>(equal-posn<#57092#> <#57093#>a<#57093#> <#57094#>b))<#57094#> 
It defines two <#70014#><#57098#>posn<#57098#><#70014#> structures. The two structures are initially equal in the sense of the preceding subsection. Yet when we evaluate the <#57099#>begin<#57099#>-expression, the result is <#70015#><#57100#>false<#57100#><#70015#>. Even though the two structures initially consist of the same values, they are different because the structure mutation in the <#57101#>begin<#57101#>-expression\ changes the <#70016#><#57102#>x<#57102#><#70016#>-field of the first structure and leaves the second one alone. More generally, the expression has an effect on one structure but not the other. Now take a look at a slightly different program:
<#57107#>(define<#57107#> <#57108#>a<#57108#> <#57109#>(make-posn<#57109#> <#57110#>12<#57110#> <#57111#>1))<#57111#>
<#57112#>(define<#57112#> <#57113#>b<#57113#> <#57114#>a)<#57114#> 
<#57115#>(b<#57115#><#57116#>egin<#57116#> 
  <#57117#>(set-posn-x!<#57117#> <#57118#>a<#57118#> <#57119#>1)<#57119#> 
  <#57120#>(equal-posn<#57120#> <#57121#>a<#57121#> <#57122#>b))<#57122#> 
Here <#70017#><#57126#>a<#57126#><#70017#> and <#70018#><#57127#>b<#57127#><#70018#> are two different names for the same structure. Therefore, the evaluation of <#70019#><#57128#>(set-posn-x!<#57128#>\ <#57129#>a<#57129#>\ <#57130#>1)<#57130#><#70019#> affects both <#70020#><#57131#>a<#57131#><#70020#> and <#70021#><#57132#>b<#57132#><#70021#>, which means that <#70022#><#57133#>(equal-posn<#57133#>\ <#57134#>a<#57134#>\ <#57135#>b)<#57135#><#70022#> is going to yield <#70023#><#57136#>true<#57136#><#70023#> this time. The two observations have a general moral. If the evaluation of an expression affects one structure and simultaneously some other structure, the two structures are equal in a deeper sense than <#70024#><#57137#>equal-posn<#57137#><#70024#> can determine. Philosophers refer to this notion of equality as <#70025#><#57138#>INTENSIONAL EQUALITY<#57138#><#70025#>. In contrast to extensional equality, this notion of equality requires not only that two structures consist of equal parts, but that they also simultaneously react to structure mutations. It is a direct consequence that two intensionally equal structures are also extensionally equal. Designing a function for determining the intensional equality of structures is more work than designing one for determining their extensional equality. We start with a precise description:
<#72047#>;; <#70026#><#57143#>eq-posn?<#57143#> <#57144#>:<#57144#> <#57145#>posn<#57145#> <#57146#>posn<#57146#> <#57147#><#57147#><#57148#>-;SPMgt;<#57148#><#57149#><#57149#> <#57150#>boolean<#57150#><#70026#><#72047#>
<#72048#>;; to determine whether two <#70027#><#57151#>posn<#57151#><#70027#> structures <#72048#> 
<#57152#>;; are affected by the same mutation <#57152#> 
<#57153#>(define<#57153#> <#57154#>(equal-posn<#57154#> <#57155#>p1<#57155#> <#57156#>p2)<#57156#> <#57157#>...)<#57157#> 
We already have an example, so we move on to a discussion of the template:
<#57165#>(d<#57165#><#57166#>efine<#57166#> <#57167#>(eq-posn<#57167#> <#57168#>p1<#57168#> <#57169#>p2)<#57169#>
  <#57170#>...<#57170#> <#57171#>(posn-x<#57171#> <#57172#>p1)<#57172#> <#57173#>...<#57173#> <#57174#>(posn-x<#57174#> <#57175#>p2)<#57175#> <#57176#>...<#57176#> 
  <#57177#>...<#57177#> <#57178#>(posn-y<#57178#> <#57179#>p1)<#57179#> <#57180#>...<#57180#> <#57181#>(posn-y<#57181#> <#57182#>p2)<#57182#> <#57183#>...<#57183#> <#57184#>)<#57184#> 
The template contains of four expressions, each one reminding us of the available information and which structure fields we can mutate. Translating the above observations into a full definition yields the following draft:
<#57192#>(d<#57192#><#57193#>efine<#57193#> <#57194#>(equal-posn<#57194#> <#57195#>p1<#57195#> <#57196#>p2)<#57196#>
  <#57197#>(b<#57197#><#57198#>egin<#57198#> 
    <#57199#>(set-posn-x!<#57199#> <#57200#>p1<#57200#> <#57201#>5)<#57201#> 
    <#57202#>(=<#57202#> <#57203#>(posn-x<#57203#> <#57204#>p2)<#57204#> <#57205#>5)))<#57205#> 
This function sets <#70028#><#57209#>p1<#57209#><#70028#>'s <#70029#><#57210#>x<#57210#><#70029#>-field to <#70030#><#57211#>5<#57211#><#70030#> and then checks whether <#70031#><#57212#>p2<#57212#><#70031#>'s <#70032#><#57213#>x<#57213#><#70032#>-field also became <#70033#><#57214#>5<#57214#><#70033#>. If so, both structures reacted to the mutation and are, by definition, intensionally equal. Unfortunately, our reasoning has a problem. Consider the following application:
<#57219#>(eq-posn<#57219#> <#57220#>(make-posn<#57220#> <#57221#>1<#57221#> <#57222#>2)<#57222#> <#57223#>(make-posn<#57223#> <#57224#>5<#57224#> <#57225#>6))<#57225#>
The two <#70034#><#57229#>posn<#57229#><#70034#>'s aren't even extensionally equivalent, so they should not be intensionally equivalent. But our first version of <#70035#><#57230#>eq-posn<#57230#><#70035#> would produce <#70036#><#57231#>true<#57231#><#70036#>, and that is a problem. We can improve the first version with a second mutation:
<#57236#>(d<#57236#><#57237#>efine<#57237#> <#57238#>(equal-posn<#57238#> <#57239#>p1<#57239#> <#57240#>p2)<#57240#>
  <#57241#>(b<#57241#><#57242#>egin<#57242#> 
    <#57243#>(set-posn-x!<#57243#> <#57244#>p1<#57244#> <#57245#>5)<#57245#> 
    <#57246#>(set-posn-x!<#57246#> <#57247#>p2<#57247#> <#57248#>6)<#57248#> 
    <#57249#>(=<#57249#> <#57250#>(posn-x<#57250#> <#57251#>p1)<#57251#> <#57252#>6)))<#57252#> 
This function changes <#70037#><#57256#>p1<#57256#><#70037#> and then <#70038#><#57257#>p2<#57257#><#70038#>. If the structures are intensionally equal, then the mutation of <#70039#><#57258#>p2<#57258#><#70039#> must affect <#70040#><#57259#>p1<#57259#><#70040#>. Furthermore, we know that <#70041#><#57260#>p1<#57260#><#70041#>'s <#70042#><#57261#>x<#57261#><#70042#>-field can't be coincidentally contain <#70043#><#57262#>6<#57262#><#70043#>, because we first changed it to~<#70044#><#57263#>5<#57263#><#70044#>. Thus, when <#70045#><#57264#>(equal-posn<#57264#>\ <#57265#>a<#57265#>\ <#57266#>b)<#57266#><#70045#> produces <#70046#><#57267#>true<#57267#><#70046#>, <#70047#><#57268#>a<#57268#><#70047#> changes when <#70048#><#57269#>b<#57269#><#70048#> changes and <#57270#>vice versa<#57270#>, and the structures are intensionally equal. The only problem left now is that <#70049#><#57271#>equal-posn<#57271#><#70049#> has effects on the two structures that it consumes but has no effect statement. Indeed, it should not have a visible effect because its only purpose is to determine whether two structures are intensionally equal. We can avoid this effect by first saving the old values in <#70050#><#57272#>p1<#57272#><#70050#>'s and <#70051#><#57273#>p2<#57273#><#70051#>'s <#70052#><#57274#>x<#57274#><#70052#> fields, mutating the fields, and then restoring the old values. Figure~#figeq#57275> contains a function definition that performs an intensional equality check without any visible effects.
<#72049#>;; <#70053#><#57280#>eq-posn?<#57280#> <#57281#>:<#57281#> <#57282#>posn<#57282#> <#57283#>posn<#57283#> <#57284#><#57284#><#57285#>-;SPMgt;<#57285#><#57286#><#57286#> <#57287#>boolean<#57287#><#70053#><#72049#>
<#72050#>;; to determine whether two <#70054#><#57288#>posn<#57288#><#70054#> structures <#72050#> 
<#57289#>;; are affected by the same mutation <#57289#> 
<#57290#>(d<#57290#><#57291#>efine<#57291#> <#57292#>(equal-posn<#57292#> <#57293#>p1<#57293#> <#57294#>p2)<#57294#> 
  <#57295#>(l<#57295#><#57296#>ocal<#57296#> <#57297#>(<#57297#><#72051#>;; save old <#70055#><#57298#>x<#57298#><#70055#> values of <#70056#><#57299#>p1<#57299#><#70056#> and <#70057#><#57300#>p2<#57300#><#70057#><#72051#> 
          <#57301#>(define<#57301#> <#57302#>old-x1<#57302#> <#57303#>(posn-x<#57303#> <#57304#>p1))<#57304#> 
          <#57305#>(define<#57305#> <#57306#>old-x2<#57306#> <#57307#>(posn-x<#57307#> <#57308#>p2))<#57308#> 
          <#72052#>;; modify both <#70058#><#57309#>x<#57309#><#70058#> fields of <#70059#><#57310#>p1<#57310#><#70059#> and <#70060#><#57311#>p2<#57311#><#70060#><#72052#> 
          <#57312#>(define<#57312#> <#57313#>effect1<#57313#> <#57314#>(set-posn-x!<#57314#> <#57315#>p1<#57315#> <#57316#>5))<#57316#> 
          <#57317#>(define<#57317#> <#57318#>effect2<#57318#> <#57319#>(set-posn-x!<#57319#> <#57320#>p2<#57320#> <#57321#>6))<#57321#> 
          <#57322#>;; now compare the two fields<#57322#> 
          <#57323#>(define<#57323#> <#57324#>same<#57324#> <#57325#>(=<#57325#> <#57326#>(posn-x<#57326#> <#57327#>p1)<#57327#> <#57328#>(posn-x<#57328#> <#57329#>p2)))<#57329#> 
          <#57330#>;; restore old values<#57330#> 
          <#57331#>(define<#57331#> <#57332#>effect3<#57332#> <#57333#>(set-posn-x!<#57333#> <#57334#>p1<#57334#> <#57335#>old-x1))<#57335#> 
          <#57336#>(define<#57336#> <#57337#>effect4<#57337#> <#57338#>(set-posn-x!<#57338#> <#57339#>p2<#57339#> <#57340#>old-x2)))<#57340#> 
    <#57341#>same))<#57341#> 
<#57345#>Figure: Determining the intensional equality of two structures<#57345#>
The existence of <#70061#><#57347#>eq-posn?<#57347#><#70061#> says that all structures have a unique ``finger print''. We can inspect two structures (of the same class) for this finger print if we have access to the mutators. Scheme and many other languages typically provide built-in functions for comparing two structural values extensionally and intensionally. The corresponding functions in Scheme are <#70062#><#57348#>equal?<#57348#><#70062#> and <#70063#><#57349#>eq?<#57349#><#70063#>. As a matter of fact, in Scheme, both functions are applicable to all values, whether mutators and selectors are accessible or hidden. Still, programmers should use equality functions that indicate what kind of values they expect to compare, such as <#70064#><#57350#>symbol=?<#57350#><#70064#>, <#70065#><#57351#>boolean?<#57351#><#70065#>, or <#70066#><#57352#>=<#57352#><#70066#>, because the additional information helps readers understand the purpose of the program more easily.
<#57355#>Exercise 42.2.1<#57355#> Evaluate the following expressions by hand:
<#57361#>1.<#57361#> <#57362#>(eq-posn?<#57362#> <#57363#>(make-posn<#57363#> <#57364#>1<#57364#> <#57365#>2)<#57365#> <#57366#>(make-posn<#57366#> <#57367#>1<#57367#> <#57368#>2))<#57368#>
<#57369#>2.<#57369#> <#57370#>(local<#57370#> <#57371#>((define<#57371#> <#57372#>p<#57372#> <#57373#>(make-posn<#57373#> <#57374#>1<#57374#> <#57375#>2)))<#57375#> 
          <#57376#>(eq-posn?<#57376#> <#57377#>p<#57377#> <#57378#>p))<#57378#> 
<#57379#>3.<#57379#> <#57380#>(local<#57380#> <#57381#>((def<#57381#><#57382#>ine<#57382#> <#57383#>p<#57383#> <#57384#>(make-posn<#57384#> <#57385#>1<#57385#> <#57386#>2))<#57386#> 
               <#57387#>(define<#57387#> <#57388#>a<#57388#> <#57389#>(list<#57389#> <#57390#>p)))<#57390#> 
          <#57391#>(eq-posn?<#57391#> <#57392#>(first<#57392#> <#57393#>a)<#57393#> <#57394#>p))<#57394#> 
Check the answers with DrScheme.~ external Solution<#70067#><#70067#> <#57403#>Exercise 42.2.2<#57403#> Develop an intensional equality function for the class of <#70068#><#57405#>child<#57405#><#70068#> structures from exercise~#exftss1#57406>. If <#70069#><#57407#>ft1<#57407#><#70069#> and <#70070#><#57408#>ft2<#57408#><#70070#> are family tree nodes, how long is the maximal abstract running time of the function?~ external Solution<#70071#><#70071#> <#57414#>Exercise 42.2.3<#57414#> Use exercise~#exeqintensional1#57416> to abstract <#70072#><#57417#>eq-posn<#57417#><#70072#> so that its instances can test the intensional equality of any given class of structures.~ external Solution<#70073#><#70073#>