Hi all - <div><br></div><div>I have a couple of questions on how hash works. What I am trying to do is that I am using a struct as the hash key. The struct has the following definition: </div><div><br></div><blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;">
<div><font class="Apple-style-span" face="'courier new', monospace">(define-struct foo (name)) ;; there are other fields but simplified for this exercise </font></div></blockquote><div><br></div><div>The name field holds a symbol. Because my actual struct holds quite a bit of complex structure that my code does not hold elsewhere, instead of trying to keep another hash that holds the mapping between the name and the struct, I want to make the name and the struct equivalent from hash's perspective, so I can pass in the symbol to the hash and it will be mapped to the right struct that maps to the corresponding value. </div>
<div><br></div><div>After much experimentation, I achieve the above goal with the following: </div><div><br></div><div>1 - leverage <font class="Apple-style-span" face="'courier new', monospace">prop:equal+hash</font> property. This defines an <font class="Apple-style-span" face="'courier new', monospace">equal?</font>, <font class="Apple-style-span" face="'courier new', monospace">equal-hash-code</font>, and <font class="Apple-style-span" face="'courier new', monospace">equal-secondary-hash-code</font> for the struct. My definition of foo is updated as follows:</div>
<div><br></div><blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;"><div><div><font class="Apple-style-span" face="'courier new', monospace"><div>(define-struct foo (name)</div>
<div> #:property prop:equal+hash </div><div> (let () </div><div> (define (equal/foo? $s1 $s2 recur) </div><div> (equal? (foo-name $s1) (foo-name $s2))) </div><div> (define (equal-hash-code/foo $s recur) </div>
<div> (- (equal-hash-code (foo-name $s)) <b>35</b>)) </div><div> (define (equal-secondary-hash-code/foo $s recur) </div><div> (equal-secondary-hash-code $s))</div><div> (list equal/foo? equal-hash-code/foo equal-secondary-hash-code/foo)))</div>
</font></div></div></blockquote><div><br></div><div>What's interesting is that I need to adjust the value from equal-hash-code by 35 in order to get (equal-hash-code 'test) and (equal-hash-code (make-foo 'test)) to be the same. For equal-secondary-hash-code such adjustment is not required. So the first question - why do equal-hash-code require such adjustment (and why 35)? </div>
<div><br></div><div>Now - I thought that hash-ref simply compares the hash-code of the key, but that alone does not appear to be enough, as hash-ref seem to also dictate having the same types for the key, so I have to add one extra struct (called href below) to wrap around the keys: </div>
<div><br></div><blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;"><div><div><font class="Apple-style-span" face="'courier new', monospace">(define-struct href (inner) </font></div>
</div><div><div><font class="Apple-style-span" face="'courier new', monospace"> #:property prop:equal+hash </font></div></div><div><div><font class="Apple-style-span" face="'courier new', monospace"> (let () </font></div>
</div><div><div><font class="Apple-style-span" face="'courier new', monospace"> (define (equal/href? $s1 $s2 recur)</font></div></div><div><div><font class="Apple-style-span" face="'courier new', monospace"> (equal? (equal-hash-code $s1) (equal-hash-code $s2)))</font></div>
</div><div><div><font class="Apple-style-span" face="'courier new', monospace"> (define (equal-hash-code/href $s recur) </font></div></div><div><div><font class="Apple-style-span" face="'courier new', monospace"> (equal-hash-code (href-inner $s))) </font></div>
</div><div><div><font class="Apple-style-span" face="'courier new', monospace"> (define (equal-secondary-hash-code/href $s recur) </font></div></div><div><div><font class="Apple-style-span" face="'courier new', monospace"> (equal-secondary-hash-code (href-inner $s)))</font></div>
</div><div><div><font class="Apple-style-span" face="'courier new', monospace"> (list equal/href? equal-hash-code/href equal-secondary-hash-code)))</font></div></div></blockquote><div><br></div><div>I did not need to adjust the equal-hash-code for this object (not sure why here either). And now I can finally do the following: </div>
<div><br></div><blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;"><div><div><font class="Apple-style-span" face="'courier new', monospace">(hash-ref (make-immutable-hash (list (cons (make-href (make-foo 'test)) 'we-have-the-value)))</font></div>
</div><div><div><font class="Apple-style-span" face="'courier new', monospace"> (make-href 'test) 'we-do-not-have-the-value) </font></div></div><div><font class="Apple-style-span" face="'courier new', monospace">;; => 'we-have-the-value </font></div>
</blockquote><div><br></div><div>So it seems that hash-ref by default also checks the type of the key besides checking their hash-code - unless they have the same type, the keys will not match even with the same hash-code. Is that correct?</div>
<div><br></div><div>Any thoughts are appreciated. Thanks.</div><div>yc</div><div><br></div>