From 0c36eb9ae6248d71fd8252afa8d318d2ec1a042c Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Wed, 11 Mar 2009 03:40:42 +0000 Subject: [PATCH] add section to guide on structure equality svn: r14049 --- .../scribblings/guide/define-struct.scrbl | 66 +++++++++++++++++++ collects/scribblings/guide/hash-tables.scrbl | 2 +- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/collects/scribblings/guide/define-struct.scrbl b/collects/scribblings/guide/define-struct.scrbl index 20b38b3e68..60c43da8f0 100644 --- a/collects/scribblings/guide/define-struct.scrbl +++ b/collects/scribblings/guide/define-struct.scrbl @@ -188,6 +188,72 @@ can use an opaque structure to encapsulate data, and clients of the library cannot manipulate the data in the structure except as allowed by the library. +@; ------------------------------------------------------------ +@section[#:tag "struct-equal"]{Stucture Comparisons} + +A generic @scheme[equal?] comparison automatically recurs on the +fields of a transparent structure type, but @scheme[equal?] defaults +to mere instance identity for opaque structure types: + +@def+int[ +#:eval posn-eval +(define-struct glass (width height) #:transparent) +(equal? (make-glass 1 2) (make-glass 1 2)) +] +@def+int[ +#:eval posn-eval +(define-struct lead (width height)) +(define slab (make-lead 1 2)) +(equal? slab slab) +(equal? slab (make-lead 1 2)) +] + +To support instances comparisons via @scheme[equal?] without making +the structure type transparent, you can use the @scheme[#:property] +keyword, @scheme[prop:equal+hash], and then a list of three functions: + +@def+int[ +#:eval posn-eval +(define-struct lead (width height) + #:property + prop:equal+hash + (list (lambda (a b equal?-recur) + (code:comment #, @t{compare @scheme[a] and @scheme[b]}) + (and (equal?-recur (lead-width a) (lead-width b)) + (equal?-recur (lead-height a) (lead-height b)))) + (lambda (a hash-recur) + (code:comment #, @t{compute primary hash code of @scheme[a]}) + (+ (hash-recur (lead-width a)) + (* 3 (hash-recur (lead-height a))))) + (lambda (a hash2-recur) + (code:comment #, @t{compute secondary hash code of @scheme[a]}) + (+ (hash2-recur (lead-width a)) + (hash2-recur (lead-height a)))))) +(equal? (make-lead 1 2) (make-lead 1 2)) +] + +The first function in the list implements the @scheme[equal?] test on +two @scheme[lead]s; the third argument to the function is used instead +of @scheme[equal?] for recursive equality testing, so that data cycles +can be handled correctly. The other two functions compute primary and +secondary hash codes for use with @tech{hash tables}: + +@interaction[ +#:eval posn-eval +(define h (make-hash)) +(hash-set! h (make-lead 1 2) 3) +(hash-ref h (make-lead 1 2)) +(hash-ref h (make-lead 2 1)) +] + +The first function provided with @scheme[prop:equal+hash] is not +required to recursively compare the fields of the structure. For +example, a structure type representing a set might implement equality +by checking that the members of the set are the same, independent of +the order of elements in the internal representation. Just take care +that the hash functions produce the same value for any two structure +types that are supposed to be equivalent. + @; ------------------------------------------------------------ @section{Structure Type Generativity} diff --git a/collects/scribblings/guide/hash-tables.scrbl b/collects/scribblings/guide/hash-tables.scrbl index 5db068be03..210e7edc42 100644 --- a/collects/scribblings/guide/hash-tables.scrbl +++ b/collects/scribblings/guide/hash-tables.scrbl @@ -5,7 +5,7 @@ @title[#:tag "hash-tables"]{Hash Tables} -A @defterm{hash table} implements a mapping from keys to values, where +A @deftech{hash table} implements a mapping from keys to values, where both keys and values can be arbitrary Scheme values, and access and update to the table are normally constant-time operations. Keys are compared using @scheme[equal?] or @scheme[eq?], depending on whether