Have a generic interface for equal+hash.
Currently provided by racket/struct, for lack of a better place.
This commit is contained in:
parent
cc7ae795ea
commit
390cd02b52
|
@ -4,7 +4,8 @@
|
||||||
unstable/wrapc)
|
unstable/wrapc)
|
||||||
racket/contract/base
|
racket/contract/base
|
||||||
racket/dict
|
racket/dict
|
||||||
racket/vector)
|
racket/vector
|
||||||
|
racket/struct)
|
||||||
|
|
||||||
(define (make-gvector #:capacity [capacity 10])
|
(define (make-gvector #:capacity [capacity 10])
|
||||||
(gvector (make-vector capacity #f) 0))
|
(gvector (make-vector capacity #f) 0))
|
||||||
|
@ -192,9 +193,8 @@
|
||||||
any/c
|
any/c
|
||||||
exact-nonnegative-integer?
|
exact-nonnegative-integer?
|
||||||
#f #f #f))
|
#f #f #f))
|
||||||
#:property prop:equal+hash
|
#:methods gen:equal+hash
|
||||||
(let ([equals
|
[(define (equal-proc x y recursive-equal?)
|
||||||
(lambda (x y recursive-equal?)
|
|
||||||
(let ([vx (gvector-vec x)]
|
(let ([vx (gvector-vec x)]
|
||||||
[vy (gvector-vec y)]
|
[vy (gvector-vec y)]
|
||||||
[nx (gvector-n x)]
|
[nx (gvector-n x)]
|
||||||
|
@ -202,15 +202,15 @@
|
||||||
(and (= nx ny)
|
(and (= nx ny)
|
||||||
(for/and ([index (in-range nx)])
|
(for/and ([index (in-range nx)])
|
||||||
(recursive-equal? (vector-ref vx index)
|
(recursive-equal? (vector-ref vx index)
|
||||||
(vector-ref vy index))))))]
|
(vector-ref vy index))))))
|
||||||
[hash-code
|
(define (hash-code x hc)
|
||||||
(lambda (x hc)
|
|
||||||
(let ([v (gvector-vec x)]
|
(let ([v (gvector-vec x)]
|
||||||
[n (gvector-n x)])
|
[n (gvector-n x)])
|
||||||
(for/fold ([h 1]) ([i (in-range n)])
|
(for/fold ([h 1]) ([i (in-range n)])
|
||||||
;; FIXME: better way of combining hashcodes
|
;; FIXME: better way of combining hashcodes
|
||||||
(+ h (hc (vector-ref v i))))))])
|
(+ h (hc (vector-ref v i))))))
|
||||||
(list equals hash-code hash-code))
|
(define hash-proc hash-code)
|
||||||
|
(define hash2-proc hash-code)]
|
||||||
#:property prop:sequence in-gvector)
|
#:property prop:sequence in-gvector)
|
||||||
|
|
||||||
(provide/contract
|
(provide/contract
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
racket/promise
|
racket/promise
|
||||||
racket/bool
|
racket/bool
|
||||||
racket/stream
|
racket/stream
|
||||||
|
racket/struct
|
||||||
racket/sequence
|
racket/sequence
|
||||||
racket/local
|
racket/local
|
||||||
racket/system
|
racket/system
|
||||||
|
@ -59,6 +60,7 @@
|
||||||
racket/promise
|
racket/promise
|
||||||
racket/bool
|
racket/bool
|
||||||
racket/stream
|
racket/stream
|
||||||
|
racket/struct
|
||||||
racket/sequence
|
racket/sequence
|
||||||
racket/local
|
racket/local
|
||||||
racket/system)
|
racket/system)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
|
|
||||||
(require racket/private/generics ; to avoid circular dependencies
|
(require racket/private/generics ; to avoid circular dependencies
|
||||||
|
racket/struct
|
||||||
(for-syntax racket/base))
|
(for-syntax racket/base))
|
||||||
|
|
||||||
(define-generics (dict gen:dict prop:dict dict? #:defined-table dict-def-table
|
(define-generics (dict gen:dict prop:dict dict? #:defined-table dict-def-table
|
||||||
|
@ -435,14 +436,16 @@
|
||||||
(define dict-iterate-next custom-hash-iterate-next)
|
(define dict-iterate-next custom-hash-iterate-next)
|
||||||
(define dict-iterate-key custom-hash-iterate-key)
|
(define dict-iterate-key custom-hash-iterate-key)
|
||||||
(define dict-iterate-value custom-hash-iterate-value)]
|
(define dict-iterate-value custom-hash-iterate-value)]
|
||||||
#:property prop:equal+hash
|
#:methods gen:equal+hash
|
||||||
(list (lambda (a b recur)
|
[(define (equal-proc a b recur)
|
||||||
(and (recur (custom-hash-make-box a)
|
(and (recur (custom-hash-make-box a)
|
||||||
(custom-hash-make-box b))
|
(custom-hash-make-box b))
|
||||||
(recur (custom-hash-table a)
|
(recur (custom-hash-table a)
|
||||||
(custom-hash-table b))))
|
(custom-hash-table b))))
|
||||||
(lambda (a recur) (recur (custom-hash-table a)))
|
(define (hash-proc a recur)
|
||||||
(lambda (a recur) (recur (custom-hash-table a)))))
|
(recur (custom-hash-table a)))
|
||||||
|
(define (hash2-proc a recur)
|
||||||
|
(recur (custom-hash-table a)))])
|
||||||
|
|
||||||
(struct immutable-custom-hash custom-hash ()
|
(struct immutable-custom-hash custom-hash ()
|
||||||
#:methods gen:dict
|
#:methods gen:dict
|
||||||
|
@ -471,13 +474,13 @@
|
||||||
(raise-type-error who "procedure (arity 1)" hash2))
|
(raise-type-error who "procedure (arity 1)" hash2))
|
||||||
(let ()
|
(let ()
|
||||||
(struct box hash-box ()
|
(struct box hash-box ()
|
||||||
#:property prop:equal+hash (list
|
#:methods gen:equal+hash
|
||||||
(lambda (a b recur)
|
[(define (equal-proc a b recur)
|
||||||
(=? (hash-box-key a) (hash-box-key b)))
|
(=? (hash-box-key a) (hash-box-key b)))
|
||||||
(lambda (v recur)
|
(define (hash-proc v recur)
|
||||||
(hash (hash-box-key v)))
|
(hash (hash-box-key v)))
|
||||||
(lambda (v recur)
|
(define (hash2-proc v recur)
|
||||||
(hash2 (hash-box-key v)))))
|
(hash2 (hash-box-key v)))])
|
||||||
(make-custom-hash table (wrap-make-box box))))])
|
(make-custom-hash table (wrap-make-box box))))])
|
||||||
(let ([make-custom-hash
|
(let ([make-custom-hash
|
||||||
(lambda (=? hash [hash2 (lambda (v) 10001)])
|
(lambda (=? hash [hash2 (lambda (v) 10001)])
|
||||||
|
|
33
collects/racket/struct.rkt
Normal file
33
collects/racket/struct.rkt
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#lang racket/base
|
||||||
|
|
||||||
|
;; Provides generic interfaces that correspond to struct properties
|
||||||
|
;; that live in racket/base
|
||||||
|
|
||||||
|
(require racket/private/generics)
|
||||||
|
|
||||||
|
(provide gen:equal+hash)
|
||||||
|
|
||||||
|
(define-values (prop:gen:equal+hash equal+hash? gen:equal+hash-acc)
|
||||||
|
(make-struct-type-property
|
||||||
|
'prop:gen:equal+hash
|
||||||
|
(lambda (v si)
|
||||||
|
(unless (and (vector? v)
|
||||||
|
(= 3 (vector-length v))
|
||||||
|
(procedure? (vector-ref v 0))
|
||||||
|
(procedure-arity-includes? (vector-ref v 0) 3)
|
||||||
|
(procedure? (vector-ref v 1))
|
||||||
|
(procedure-arity-includes? (vector-ref v 1) 2)
|
||||||
|
(procedure? (vector-ref v 2))
|
||||||
|
(procedure-arity-includes? (vector-ref v 2) 2))
|
||||||
|
(raise-type-error 'guard-for-prop:gen:equal+hash
|
||||||
|
"vector of three procedures (arities 3, 2, 2)"
|
||||||
|
v))
|
||||||
|
v)
|
||||||
|
(list (cons prop:equal+hash vector->list))))
|
||||||
|
|
||||||
|
(define-generics (equal+hash gen:equal+hash prop:gen:equal+hash equal+hash?
|
||||||
|
#:defined-table dummy
|
||||||
|
#:prop-defined-already? gen:equal+hash-acc)
|
||||||
|
(equal-proc equal+hash rhs equal?/recur)
|
||||||
|
(hash-proc equal+hash equal-hash-code/recur)
|
||||||
|
(hash2-proc equal+hash equal-secondary-hash-code/recur))
|
|
@ -1,8 +1,9 @@
|
||||||
#lang scribble/doc
|
#lang scribble/doc
|
||||||
@(require scribble/manual scribble/eval scribble/bnf "guide-utils.rkt"
|
@(require scribble/manual scribble/eval scribble/bnf "guide-utils.rkt"
|
||||||
(for-label racket/serialize))
|
(for-label racket/serialize racket/struct))
|
||||||
|
|
||||||
@(define posn-eval (make-base-eval))
|
@(define posn-eval (make-base-eval))
|
||||||
|
@(posn-eval '(require racket/struct))
|
||||||
|
|
||||||
@title[#:tag "define-struct"]{Programmer-Defined Datatypes}
|
@title[#:tag "define-struct"]{Programmer-Defined Datatypes}
|
||||||
|
|
||||||
|
@ -198,26 +199,26 @@ to mere instance identity for opaque structure types:
|
||||||
]
|
]
|
||||||
|
|
||||||
To support instances comparisons via @racket[equal?] without making
|
To support instances comparisons via @racket[equal?] without making
|
||||||
the structure type transparent, you can use the @racket[#:property]
|
the structure type transparent, you can use the @racket[#:methods]
|
||||||
keyword, @racket[prop:equal+hash], and then a list of three functions:
|
keyword, @racket[gen:equal+hash], and implement three methods:
|
||||||
|
|
||||||
@def+int[
|
@def+int[
|
||||||
#:eval posn-eval
|
#:eval posn-eval
|
||||||
(struct lead (width height)
|
(struct lead (width height)
|
||||||
#:property
|
#:methods
|
||||||
prop:equal+hash
|
gen:equal+hash
|
||||||
(list (lambda (a b equal?-recur)
|
[(define (equal-proc a b equal?-recur)
|
||||||
(code:comment @#,t{compare @racket[a] and @racket[b]})
|
(code:comment @#,t{compare @racket[a] and @racket[b]})
|
||||||
(and (equal?-recur (lead-width a) (lead-width b))
|
(and (equal?-recur (lead-width a) (lead-width b))
|
||||||
(equal?-recur (lead-height a) (lead-height b))))
|
(equal?-recur (lead-height a) (lead-height b))))
|
||||||
(lambda (a hash-recur)
|
(define (hash-proc a hash-recur)
|
||||||
(code:comment @#,t{compute primary hash code of @racket[a]})
|
(code:comment @#,t{compute primary hash code of @racket[a]})
|
||||||
(+ (hash-recur (lead-width a))
|
(+ (hash-recur (lead-width a))
|
||||||
(* 3 (hash-recur (lead-height a)))))
|
(* 3 (hash-recur (lead-height a)))))
|
||||||
(lambda (a hash2-recur)
|
(define (hash2-proc a hash2-recur)
|
||||||
(code:comment @#,t{compute secondary hash code of @racket[a]})
|
(code:comment @#,t{compute secondary hash code of @racket[a]})
|
||||||
(+ (hash2-recur (lead-width a))
|
(+ (hash2-recur (lead-width a))
|
||||||
(hash2-recur (lead-height a))))))
|
(hash2-recur (lead-height a))))])
|
||||||
(equal? (lead 1 2) (lead 1 2))
|
(equal? (lead 1 2) (lead 1 2))
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -235,7 +236,7 @@ secondary hash codes for use with @tech{hash tables}:
|
||||||
(hash-ref h (lead 2 1))
|
(hash-ref h (lead 2 1))
|
||||||
]
|
]
|
||||||
|
|
||||||
The first function provided with @racket[prop:equal+hash] is not
|
The first function provided with @racket[gen:equal+hash] is not
|
||||||
required to recursively compare the fields of the structure. For
|
required to recursively compare the fields of the structure. For
|
||||||
example, a structure type representing a set might implement equality
|
example, a structure type representing a set might implement equality
|
||||||
by checking that the members of the set are the same, independent of
|
by checking that the members of the set are the same, independent of
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
@(define bool-eval (make-base-eval))
|
@(define bool-eval (make-base-eval))
|
||||||
@(bool-eval '(require racket/bool))
|
@(bool-eval '(require racket/bool))
|
||||||
|
|
||||||
|
@(define struct-eval (make-base-eval))
|
||||||
|
@(struct-eval '(require racket/struct))
|
||||||
|
|
||||||
@title[#:tag "booleans"]{Booleans and Equality}
|
@title[#:tag "booleans"]{Booleans and Equality}
|
||||||
|
|
||||||
True and false @deftech{booleans} are represented by the values
|
True and false @deftech{booleans} are represented by the values
|
||||||
|
@ -50,7 +53,7 @@ strings, byte strings, pairs, mutable pairs, vectors, boxes, hash
|
||||||
tables, and inspectable structures. In the last six cases, equality
|
tables, and inspectable structures. In the last six cases, equality
|
||||||
is recursively defined; if both @racket[v1] and @racket[v2] contain
|
is recursively defined; if both @racket[v1] and @racket[v2] contain
|
||||||
reference cycles, they are equal when the infinite unfoldings of the
|
reference cycles, they are equal when the infinite unfoldings of the
|
||||||
values would be equal. See also @racket[prop:equal+hash] and @racket[prop:impersonator-of].
|
values would be equal. See also @racket[gen:equal+hash] and @racket[prop:impersonator-of].
|
||||||
|
|
||||||
@examples[
|
@examples[
|
||||||
(equal? 'yes 'yes)
|
(equal? 'yes 'yes)
|
||||||
|
@ -126,17 +129,28 @@ Returns @racket[#t] if @racket[v] is an immutable @tech{string},
|
||||||
|
|
||||||
@defthing[prop:equal+hash struct-type-property?]{
|
@defthing[prop:equal+hash struct-type-property?]{
|
||||||
|
|
||||||
A @tech{structure type property} (see @secref["structprops"]) that
|
A deprecated @tech{structure type property} (see @secref["structprops"])
|
||||||
|
that supplies an equality predicate and hashing functions for a structure
|
||||||
|
type. @racket[gen:equal+hash] should be used instead. Accepts a list of
|
||||||
|
three procedures that correspond to the methods of @racket[gen:equal+hash].
|
||||||
|
}
|
||||||
|
|
||||||
|
@section{Extensible Equality and Hashing}
|
||||||
|
|
||||||
|
@note-lib[racket/struct]
|
||||||
|
|
||||||
|
@defthing[gen:equal+hash any/c]{
|
||||||
|
A @tech{generic interface} (see @secref["struct-generics"]) that
|
||||||
supplies an equality predicate and hashing functions for a structure
|
supplies an equality predicate and hashing functions for a structure
|
||||||
type. The property value must be a list of three procedures:
|
type. The following methods must be implemented:
|
||||||
|
|
||||||
@itemize[
|
@itemize[
|
||||||
|
|
||||||
@item{@racket[_equal-proc : (any/c any/c (any/c any/c . ->
|
@item{@racket[_equal-proc : (any/c any/c (any/c any/c . ->
|
||||||
. boolean?) . -> . any/c)] --- tests whether the first two
|
. boolean?) . -> . any/c)] --- tests whether the first two
|
||||||
arguments are equal, where both values are instances of the
|
arguments are equal, where both values are instances of the
|
||||||
structure type to which the property is associated (or a
|
structure type to which the generic interface is associated
|
||||||
subtype of the structure type).
|
(or a subtype of the structure type).
|
||||||
|
|
||||||
The third argument is an @racket[equal?] predicate to use for
|
The third argument is an @racket[equal?] predicate to use for
|
||||||
recursive equality checks; use the given predicate instead of
|
recursive equality checks; use the given predicate instead of
|
||||||
|
@ -149,7 +163,7 @@ type. The property value must be a list of three procedures:
|
||||||
|
|
||||||
The @racket[_equal-proc] is called for a pair of structures
|
The @racket[_equal-proc] is called for a pair of structures
|
||||||
only when they are not @racket[eq?], and only when they both
|
only when they are not @racket[eq?], and only when they both
|
||||||
have a @racket[prop:equal+hash] value inherited from the same
|
have a @racket[gen:equal+hash] value inherited from the same
|
||||||
structure type. With this strategy, the order in which
|
structure type. With this strategy, the order in which
|
||||||
@racket[equal?] receives two structures does not matter. It
|
@racket[equal?] receives two structures does not matter. It
|
||||||
also means that, by default, a structure sub-type inherits the
|
also means that, by default, a structure sub-type inherits the
|
||||||
|
@ -159,7 +173,7 @@ type. The property value must be a list of three procedures:
|
||||||
. exact-integer?)] --- computes a hash code for the given
|
. exact-integer?)] --- computes a hash code for the given
|
||||||
structure, like @racket[equal-hash-code]. The first argument is
|
structure, like @racket[equal-hash-code]. The first argument is
|
||||||
an instance of the structure type (or one of its subtypes) to
|
an instance of the structure type (or one of its subtypes) to
|
||||||
which the property is associated.
|
which the generic interface is associated.
|
||||||
|
|
||||||
The second argument is an @racket[equal-hash-code]-like
|
The second argument is an @racket[equal-hash-code]-like
|
||||||
procedure to use for recursive hash-code computation; use the
|
procedure to use for recursive hash-code computation; use the
|
||||||
|
@ -179,7 +193,7 @@ are consistent with @racket[_equal-proc]. Specifically,
|
||||||
value for any two structures for which @racket[_equal-proc] produces a
|
value for any two structures for which @racket[_equal-proc] produces a
|
||||||
true value.
|
true value.
|
||||||
|
|
||||||
When a structure type has no @racket[prop:equal+hash] property, then
|
When a structure type has no @racket[gen:equal+hash] implementation, then
|
||||||
transparent structures (i.e., structures with an @tech{inspector} that
|
transparent structures (i.e., structures with an @tech{inspector} that
|
||||||
is controlled by the current @tech{inspector}) are @racket[equal?]
|
is controlled by the current @tech{inspector}) are @racket[equal?]
|
||||||
when they are instances of the same structure type (not counting
|
when they are instances of the same structure type (not counting
|
||||||
|
@ -191,10 +205,10 @@ values. For opaque structure types, @racket[equal?] is the same as
|
||||||
@racket[equal-secondary-hash-code] results are based only on
|
@racket[equal-secondary-hash-code] results are based only on
|
||||||
@racket[eq-hash-code]. If a structure has a @racket[prop:impersonator-of]
|
@racket[eq-hash-code]. If a structure has a @racket[prop:impersonator-of]
|
||||||
property, then the @racket[prop:impersonator-of] property takes precedence over
|
property, then the @racket[prop:impersonator-of] property takes precedence over
|
||||||
@racket[prop:equal+hash] if the property value's procedure returns a
|
@racket[gen:equal+hash] if the property value's procedure returns a
|
||||||
non-@racket[#f] value when applied to the structure.
|
non-@racket[#f] value when applied to the structure.
|
||||||
|
|
||||||
@examples[
|
@examples[ #:eval struct-eval
|
||||||
(define (farm=? farm1 farm2 recursive-equal?)
|
(define (farm=? farm1 farm2 recursive-equal?)
|
||||||
(and (= (farm-apples farm1)
|
(and (= (farm-apples farm1)
|
||||||
(farm-apples farm2))
|
(farm-apples farm2))
|
||||||
|
@ -213,8 +227,10 @@ non-@racket[#f] value when applied to the structure.
|
||||||
(* 1 (farm-oranges farm))))
|
(* 1 (farm-oranges farm))))
|
||||||
|
|
||||||
(define-struct farm (apples oranges sheep)
|
(define-struct farm (apples oranges sheep)
|
||||||
#:property prop:equal+hash
|
#:methods gen:equal+hash
|
||||||
(list farm=? farm-hash-1 farm-hash-2))
|
[(define equal-proc farm=?)
|
||||||
|
(define hash-proc farm-hash-1)
|
||||||
|
(define hash2-proc farm-hash-2)])
|
||||||
(define east (make-farm 5 2 20))
|
(define east (make-farm 5 2 20))
|
||||||
(define west (make-farm 18 6 14))
|
(define west (make-farm 18 6 14))
|
||||||
(define north (make-farm 5 20 20))
|
(define north (make-farm 5 20 20))
|
||||||
|
|
|
@ -655,7 +655,7 @@ iterators, respectively, if @racket[d] implements the
|
||||||
Creates a dictionary that is implemented in terms of a hash table
|
Creates a dictionary that is implemented in terms of a hash table
|
||||||
where keys are compared with @racket[eql?] and hashed with
|
where keys are compared with @racket[eql?] and hashed with
|
||||||
@racket[hash-proc] and @racket[hash2-proc]. See
|
@racket[hash-proc] and @racket[hash2-proc]. See
|
||||||
@racket[prop:equal+hash] for information on suitable equality and
|
@racket[gen:equal+hash] for information on suitable equality and
|
||||||
hashing functions.
|
hashing functions.
|
||||||
|
|
||||||
The @racket[make-custom-hash] and @racket[make-weak-custom-hash]
|
The @racket[make-custom-hash] and @racket[make-weak-custom-hash]
|
||||||
|
|
|
@ -443,7 +443,7 @@ the returned number is the same.}
|
||||||
Returns a @tech{fixnum}; for any two calls with @racket[equal?] values,
|
Returns a @tech{fixnum}; for any two calls with @racket[equal?] values,
|
||||||
the returned number is the same. A hash code is computed even when
|
the returned number is the same. A hash code is computed even when
|
||||||
@racket[v] contains a cycle through pairs, vectors, boxes, and/or
|
@racket[v] contains a cycle through pairs, vectors, boxes, and/or
|
||||||
inspectable structure fields. See also @racket[prop:equal+hash].}
|
inspectable structure fields. See also @racket[gen:equal+hash].}
|
||||||
|
|
||||||
|
|
||||||
@defproc[(equal-secondary-hash-code [v any/c]) fixnum?]{
|
@defproc[(equal-secondary-hash-code [v any/c]) fixnum?]{
|
||||||
|
|
|
@ -73,7 +73,7 @@ same structure type, no fields are opaque, and the results of applying
|
||||||
@racket[equal?]. (Consequently, @racket[equal?] testing for
|
@racket[equal?]. (Consequently, @racket[equal?] testing for
|
||||||
structures may depend on the current inspector.) A structure type can
|
structures may depend on the current inspector.) A structure type can
|
||||||
override the default @racket[equal?] definition through the
|
override the default @racket[equal?] definition through the
|
||||||
@racket[prop:equal+hash] property.
|
@racket[gen:equal+hash] @tech{generic interface}.
|
||||||
|
|
||||||
@local-table-of-contents[]
|
@local-table-of-contents[]
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
|
|
||||||
(require racket/generics
|
(require racket/generics racket/struct
|
||||||
(only-in racket/dict
|
(only-in racket/dict
|
||||||
gen:dict prop:dict
|
gen:dict prop:dict
|
||||||
dict?
|
dict?
|
||||||
|
@ -9,8 +9,7 @@
|
||||||
dict-set
|
dict-set
|
||||||
dict-remove!
|
dict-remove!
|
||||||
dict-remove
|
dict-remove
|
||||||
dict-count)
|
dict-count))
|
||||||
(only-in racket/list remove-duplicates))
|
|
||||||
|
|
||||||
(struct hash-box (key))
|
(struct hash-box (key))
|
||||||
|
|
||||||
|
@ -50,14 +49,16 @@
|
||||||
(define (dict-remove dict key)
|
(define (dict-remove dict key)
|
||||||
(error "no functional update"))
|
(error "no functional update"))
|
||||||
(define dict-count custom-hash-count)]
|
(define dict-count custom-hash-count)]
|
||||||
#:property prop:equal+hash
|
#:methods gen:equal+hash
|
||||||
(list (lambda (a b recur)
|
[(define (equal-proc a b recur)
|
||||||
(and (recur (custom-hash-make-box a)
|
(and (recur (custom-hash-make-box a)
|
||||||
(custom-hash-make-box b))
|
(custom-hash-make-box b))
|
||||||
(recur (custom-hash-table a)
|
(recur (custom-hash-table a)
|
||||||
(custom-hash-table b))))
|
(custom-hash-table b))))
|
||||||
(lambda (a recur) (recur (custom-hash-table a)))
|
(define (hash-proc a recur)
|
||||||
(lambda (a recur) (recur (custom-hash-table a)))))
|
(recur (custom-hash-table a)))
|
||||||
|
(define (hash2-proc a recur)
|
||||||
|
(recur (custom-hash-table a)))])
|
||||||
|
|
||||||
|
|
||||||
(define (make-custom-hash =? hash [hash2 (lambda (v) 10001)])
|
(define (make-custom-hash =? hash [hash2 (lambda (v) 10001)])
|
||||||
|
@ -72,11 +73,13 @@
|
||||||
(raise-type-error 'make-custom-hash "procedure (arity 1)" hash2))
|
(raise-type-error 'make-custom-hash "procedure (arity 1)" hash2))
|
||||||
(let ()
|
(let ()
|
||||||
(struct box hash-box ()
|
(struct box hash-box ()
|
||||||
#:property prop:equal+hash
|
#:methods gen:equal+hash
|
||||||
(list
|
[(define (equal-proc a b recur)
|
||||||
(lambda (a b recur) (=? (hash-box-key a) (hash-box-key b)))
|
(=? (hash-box-key a) (hash-box-key b)))
|
||||||
(lambda (v recur) (hash (hash-box-key v)))
|
(define (hash-proc v recur)
|
||||||
(lambda (v recur) (hash2 (hash-box-key v)))))
|
(hash (hash-box-key v)))
|
||||||
|
(define (hash2-proc v recur)
|
||||||
|
(hash2 (hash-box-key v)))])
|
||||||
(custom-hash (make-hash) box)))
|
(custom-hash (make-hash) box)))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
#lang racket
|
#lang racket
|
||||||
|
|
||||||
|
(require racket/struct)
|
||||||
|
|
||||||
;; vectors as method tables
|
;; vectors as method tables
|
||||||
(struct kons (kar kdr)
|
(struct kons (kar kdr)
|
||||||
#:property prop:equal+hash
|
#:methods gen:equal+hash
|
||||||
(vector 'ta
|
[(define (equal-proc x y rec)
|
||||||
(lambda (x y rec)
|
|
||||||
(and (rec (kons-kar x) (kons-kar y))
|
(and (rec (kons-kar x) (kons-kar y))
|
||||||
(rec (kons-kdr x) (kons-kdr y))))
|
(rec (kons-kdr x) (kons-kdr y))))
|
||||||
(lambda (x y) 12)
|
(define (hash-proc x rec) 12)
|
||||||
(lambda (x y) 13)))
|
(define (hash2-proc x rec) 13)])
|
||||||
|
|
||||||
(module+ test
|
(module+ test
|
||||||
(require rackunit)
|
(require rackunit)
|
||||||
|
|
|
@ -6,4 +6,5 @@
|
||||||
(submod "stream.rkt" test)
|
(submod "stream.rkt" test)
|
||||||
(submod "iterator.rkt" test)
|
(submod "iterator.rkt" test)
|
||||||
(submod "struct-form.rkt" test)
|
(submod "struct-form.rkt" test)
|
||||||
|
(submod "equal+hash.rkt" test)
|
||||||
"from-unstable.rkt")
|
"from-unstable.rkt")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user