On this page:
equal?
equal-always?
eqv?
eq?
equal?/  recur
equal-always?/  recur
4.1.1 Object Identity and Comparisons
4.1.2 Equality and Hashing
equal-hash-code
equal-hash-code/  recur
equal-secondary-hash-code
equal-always-hash-code
equal-always-hash-code/  recur
equal-always-secondary-hash-code
eq-hash-code
eqv-hash-code
4.1.3 Implementing Equality for Custom Types
gen:  equal+  hash
gen:  equal-mode+  hash
prop:  equal+  hash
4.1.4 Honest Custom Equality
4.1.5 Combining Hash Codes
hash-code-combine
hash-code-combine-unordered
hash-code-combine*
hash-code-combine-unordered*
8.10

4.1 Equality

Equality is the concept of whether two values are “the same.” Racket supports a few different kinds of equality by default, although equal? is preferred for most uses.

procedure

(equal? v1 v2)  boolean?

  v1 : any/c
  v2 : any/c
Two values are equal? if and only if they are eqv?, unless otherwise specified for a particular datatype.

Datatypes with further specification of equal? include strings, byte strings, pairs, mutable pairs, vectors, boxes, hash tables, and inspectable structures. In the last six cases, equality is recursively defined; if both v1 and v2 contain reference cycles, they are equal when the infinite unfoldings of the values would be equal. See also gen:equal+hash and prop:impersonator-of.

Examples:
> (equal? 'yes 'yes)

#t

> (equal? 'yes 'no)

#f

> (equal? (* 6 7) 42)

#t

> (equal? (expt 2 100) (expt 2 100))

#t

> (equal? 2 2.0)

#f

> (let ([v (mcons 1 2)]) (equal? v v))

#t

> (equal? (mcons 1 2) (mcons 1 2))

#t

> (equal? (integer->char 955) (integer->char 955))

#t

> (equal? (make-string 3 #\z) (make-string 3 #\z))

#t

> (equal? #t #t)

#t

procedure

(equal-always? v1 v2)  boolean?

  v1 : any/c
  v2 : any/c
Indicates whether v1 and v2 are equal and will always stay equal independent of mutations. Generally, for two values to be equal-always, corresponding immutable values within v1 and v2 must be equal?, while corresponding mutable values within them must be eq?. Precedents for this operator in other languages include egal [Baker93].

Two values v1 and v2 are equal-always? if and only if there exists a third value v3 such that v1 and v2 are both chaperones of v3, meaning (chaperone-of? v1 v3) and (chaperone-of? v2 v3) are both true.

For values that include no chaperones or other impersonators, v1 and v2 can be considered equal-always if they are equal?, except that corresponding mutable vectors, boxes, hash tables, strings, byte strings, mutable pairs, and mutable structures within v1 and v2 must be eq?, and equality on structures can be specialized for equal-always? through gen:equal-mode+hash.

Examples:
> (equal-always? 'yes 'yes)

#t

> (equal-always? 'yes 'no)

#f

> (equal-always? (* 6 7) 42)

#t

> (equal-always? (expt 2 100) (expt 2 100))

#t

> (equal-always? 2 2.0)

#f

> (equal-always? (list 1 2) (list 1 2))

#t

> (let ([v (mcons 1 2)]) (equal-always? v v))

#t

> (equal-always? (mcons 1 2) (mcons 1 2))

#f

> (equal-always? (integer->char 955) (integer->char 955))

#t

> (equal-always? (make-string 3 #\z) (make-string 3 #\z))

#f

> (equal-always? (string->immutable-string (make-string 3 #\z))
                 (string->immutable-string (make-string 3 #\z)))

#t

> (equal-always? #t #t)

#t

Added in version 8.5.0.3 of package base.

procedure

(eqv? v1 v2)  boolean?

  v1 : any/c
  v2 : any/c
Two values are eqv? if and only if they are eq?, unless otherwise specified for a particular datatype.

The number and character datatypes are the only ones for which eqv? differs from eq?. Two numbers are eqv? when they have the same exactness, precision, and are both equal and non-zero, both +0.0, both +0.0f0, both -0.0, both -0.0f0, both +nan.0, or both +nan.fconsidering real and imaginary components separately in the case of complex numbers. Two characters are eqv? when their char->integer results are equal.

Generally, eqv? is identical to equal? except that the former cannot recursively compare the contents of compound data types (such as lists and structs) and cannot be customized by user-defined data types. The use of eqv? is lightly discouraged in favor of equal?.

Examples:
> (eqv? 'yes 'yes)

#t

> (eqv? 'yes 'no)

#f

> (eqv? (* 6 7) 42)

#t

> (eqv? (expt 2 100) (expt 2 100))

#t

> (eqv? 2 2.0)

#f

> (let ([v (mcons 1 2)]) (eqv? v v))

#t

> (eqv? (mcons 1 2) (mcons 1 2))

#f

> (eqv? (integer->char 955) (integer->char 955))

#t

> (eqv? (make-string 3 #\z) (make-string 3 #\z))

#f

> (eqv? #t #t)

#t

procedure

(eq? v1 v2)  boolean?

  v1 : any/c
  v2 : any/c
Return #t if v1 and v2 refer to the same object, #f otherwise. As a special case among numbers, two fixnums that are = are also the same according to eq?. See also Object Identity and Comparisons.

Examples:
> (eq? 'yes 'yes)

#t

> (eq? 'yes 'no)

#f

> (eq? (* 6 7) 42)

#t

> (eq? (expt 2 100) (expt 2 100))

#f

> (eq? 2 2.0)

#f

> (let ([v (mcons 1 2)]) (eq? v v))

#t

> (eq? (mcons 1 2) (mcons 1 2))

#f

> (eq? (integer->char 955) (integer->char 955))

#t

> (eq? (make-string 3 #\z) (make-string 3 #\z))

#f

> (eq? #t #t)

#t

procedure

(equal?/recur v1 v2 recur-proc)  boolean?

  v1 : any/c
  v2 : any/c
  recur-proc : (any/c any/c -> any/c)
Like equal?, but using recur-proc for recursive comparisons (which means that reference cycles are not handled automatically). Non-#f results from recur-proc are converted to #t before being returned by equal?/recur.

Examples:
> (equal?/recur 1 1 (lambda (a b) #f))

#t

> (equal?/recur '(1) '(1) (lambda (a b) #f))

#f

> (equal?/recur '#(1 1 1) '#(1 1.2 3/4)
                (lambda (a b) (<= (abs (- a b)) 0.25)))

#t

procedure

(equal-always?/recur v1 v2 recur-proc)  boolean?

  v1 : any/c
  v2 : any/c
  recur-proc : (any/c any/c -> any/c)
Like equal-always?, but using recur-proc for recursive comparisons (which means that reference cycles are not handled automatically). Non-#f results from recur-proc are converted to #t before being returned by equal-always?/recur.

Examples:
> (equal-always?/recur 1 1 (lambda (a b) #f))

#t

> (equal-always?/recur '(1) '(1) (lambda (a b) #f))

#f

> (equal-always?/recur (vector-immutable 1 1 1) (vector-immutable 1 1.2 3/4)
                       (lambda (a b) (<= (abs (- a b)) 0.25)))

#t

4.1.1 Object Identity and Comparisons

The eq? operator compares two values, returning #t when the values refer to the same object. This form of equality is suitable for comparing objects that support imperative update (e.g., to determine that the effect of modifying an object through one reference is visible through another reference). Also, an eq? test evaluates quickly, and eq?-based hashing is more lightweight than equal?-based hashing in hash tables.

In some cases, however, eq? is unsuitable as a comparison operator, because the generation of objects is not clearly defined. In particular, two applications of + to the same two exact integers may or may not produce results that are eq?, although the results are always equal?. Similarly, evaluation of a lambda form typically generates a new procedure object, but it may re-use a procedure object previously generated by the same source lambda form.

The behavior of a datatype with respect to eq? is generally specified with the datatype and its associated procedures.

4.1.2 Equality and Hashing

All comparable values have at least one hash code an arbitrary integer (more specifically a fixnum) computed by applying a hash function to the value. The defining property of these hash codes is that equal values have equal hash codes. Note that the reverse is not true: two unequal values can still have equal hash codes. Hash codes are useful for various indexing and comparison operations, especially in the implementation of hash tables. See Hash Tables for more information.

procedure

(equal-hash-code v)  fixnum?

  v : any/c
Returns a hash code consistent with equal?. For any two calls with equal? values, the returned number is the same. A hash code is computed even when v contains a cycle through pairs, vectors, boxes, and/or inspectable structure fields. Additionally, user-defined data types can customize how this hash code is computed by implementing gen:equal+hash or gen:equal-mode+hash.

For any v that could be produced by read, if v2 is produced by read for the same input characters, the (equal-hash-code v) is the same as (equal-hash-code v2) even if v and v2 do not exist at the same time (and therefore could not be compared by calling equal?).

Changed in version 6.4.0.12 of package base: Strengthened guarantee for readable values.

procedure

(equal-hash-code/recur v recur-proc)  fixnum?

  v : any/c
  recur-proc : (-> any/c exact-integer?)
Like equal-hash-code, but using recur-proc for recursive hashing within v.

Examples:
> (define (rational-hash x)
    (cond
      [(rational? x) (equal-hash-code (inexact->exact x))]
      [else (equal-hash-code/recur x rational-hash)]))
> (= (rational-hash 0.0) (rational-hash -0.0))

#t

> (= (rational-hash 1.0) (rational-hash -1.0))

#f

> (= (rational-hash (list (list (list 4.0 0.0) 9.0) 6.0))
     (rational-hash (list (list (list 4 0) 9) 6)))

#t

Added in version 8.8.0.9 of package base.

procedure

(equal-secondary-hash-code v)  fixnum?

  v : any/c
Like equal-hash-code, but computes a secondary hash code suitable for use in double hashing.

procedure

(equal-always-hash-code v)  fixnum?

  v : any/c
Returns a hash code consistent with equal-always?. For any two calls with equal-always? values, the returned number is the same.

As equal-always-hash-code traverses v, immutable values within v are hashed with equal-hash-code, while mutable values within v are hashed with eq-hash-code.

procedure

(equal-always-hash-code/recur v recur-proc)  fixnum?

  v : any/c
  recur-proc : (-> any/c exact-integer?)
Like equal-always-hash-code, but using recur-proc for recursive hashing within v.

Added in version 8.8.0.9 of package base.

procedure

(equal-always-secondary-hash-code v)  fixnum?

  v : any/c
Like equal-always-hash-code, but computes a secondary hash code suitable for use in double hashing.

procedure

(eq-hash-code v)  fixnum?

  v : any/c
Returns a hash code consistent with eq?. For any two calls with eq? values, the returned number is the same.

Equal fixnums are always eq?.

procedure

(eqv-hash-code v)  fixnum?

  v : any/c
Returns a hash code consistent with eqv?. For any two calls with eqv? values, the returned number is the same.

4.1.3 Implementing Equality for Custom Types

A generic interface (see Generic Interfaces) for types that can be compared for equality using equal?. The following methods must be implemented:

Take care to ensure that hash-proc and hash2-proc are consistent with equal-proc. Specifically, hash-proc and hash2-proc should produce the same value for any two structures for which equal-proc produces a true value.

The equal-proc is not only used for equal?, it is also used for equal?/recur, and impersonator-of?. Furthermore, if the structure type has no mutable fields, equal-proc is used for equal-always?, and chaperone-of?. Likewise hash-proc and hash2-proc are used for equal-always-hash-code and equal-always-secondary-hash-code, respectively, when the structure type has no mutable fields. Instances of these methods should follow the guidelines in Honest Custom Equality to implement all of these operations reasonably. In particular, these methods should not access mutable data unless the struct is declared mutable.

When a structure type has no gen:equal+hash or gen:equal-mode+hash implementation, then transparent structures (i.e., structures with an inspector that is controlled by the current inspector) are equal? when they are instances of the same structure type (not counting sub-types), and when they have equal? field values. For transparent structures, equal-hash-code and equal-secondary-hash-code (in the case of no mutable fields) derive hash code using the field values. For a transparent structure type with at least one mutable field, equal-always? is the same as eq?, and an equal-secondary-hash-code result is based only on eq-hash-code. For opaque structure types, equal? is the same as eq?, and equal-hash-code and equal-secondary-hash-code results are based only on eq-hash-code. If a structure has a prop:impersonator-of property, then the prop:impersonator-of property takes precedence over gen:equal+hash if the property value’s procedure returns a non-#f value when applied to the structure.

Examples:
(define (farm=? farm1 farm2 recursive-equal?)
  (and (= (farm-apples farm1)
          (farm-apples farm2))
       (= (farm-oranges farm1)
          (farm-oranges farm2))
       (= (farm-sheep farm1)
          (farm-sheep farm2))))
 
(define (farm-hash-code farm recursive-equal-hash)
  (+ (* 10000 (farm-apples farm))
     (* 100 (farm-oranges farm))
     (* 1 (farm-sheep farm))))
 
(define (farm-secondary-hash-code farm recursive-equal-hash)
  (+ (* 10000 (farm-sheep farm))
     (* 100 (farm-apples farm))
     (* 1 (farm-oranges farm))))
 
(struct farm (apples oranges sheep)
  #:methods gen:equal+hash
  [(define equal-proc farm=?)
   (define hash-proc  farm-hash-code)
   (define hash2-proc farm-secondary-hash-code)])
 
(define eastern-farm (farm 5 2 20))
(define western-farm (farm 18 6 14))
(define northern-farm (farm 5 20 20))
(define southern-farm (farm 18 6 14))

 

> (equal? eastern-farm western-farm)

#f

> (equal? eastern-farm northern-farm)

#f

> (equal? western-farm southern-farm)

#t

Changed in version 8.7.0.5 of package base: Added a check so that omitting any of equal-proc, hash-proc, and hash2-proc is now a syntax error.

A generic interface (see Generic Interfaces) for types that may specify differences between equal? and equal-always?. The following methods must be implemented:

The hash-mode-proc implementation is used both for a primary hash code and secondary hash code.

When implementing these methods, follow the guidelines in Honest Custom Equality. In particular, these methods should only access mutable data if the “mode” argument is true to indicate equal? or impersonator-of?.

Implementing gen:equal-mode+hash is most useful for types that specify differences between equal? and equal-always?, such as a structure type that wraps mutable data with getter and setter procedures:

Examples:
> (define (get gs) ((getset-getter gs)))
> (define (set gs new) ((getset-setter gs) new))
> (struct getset (getter setter)
     #:methods gen:equal-mode+hash
     [(define (equal-mode-proc self other rec mode)
        (and mode (rec (get self) (get other))))
      (define (hash-mode-proc self rec mode)
        (if mode (rec (get self)) (eq-hash-code self)))])
> (define x 1)
> (define y 2)
> (define gsx (getset (lambda () x) (lambda (new) (set! x new))))
> (define gsy (getset (lambda () y) (lambda (new) (set! y new))))
> (equal? gsx gsy)

#f

> (equal-always? gsx gsy)

#f

> (set gsx 3)
> (set gsy 3)
> (equal? gsx gsy)

#t

> (equal-always? gsx gsy)

#f

> (equal-always? gsx gsx)

#t

Added in version 8.5.0.3 of package base.
Changed in version 8.7.0.5: Added a check so that omitting either equal-mode-proc or hash-mode-proc is now a syntax error.

A structure type property (see Structure Type Properties) that supplies an equality predicate and hashing functions for a structure type. Using the prop:equal+hash property is an alternative to using the gen:equal+hash or gen:equal-mode+hash generic interface.

A prop:equal+hash property value is a list of either three procedures (list equal-proc hash-proc hash2-proc) or two procedures (list equal-mode-proc hash-mode-proc):

When implementing these methods, follow the guidelines in Honest Custom Equality. In particular, these methods should only access mutable data if the struct is declared mutable or the mode is true.

Changed in version 8.5.0.3 of package base: Added support for two-procedure values to customize equal-always?.

4.1.4 Honest Custom Equality

Since the equal-proc or equal-mode-proc is used for more than just equal?, instances of them should follow certain guidelines to make sure that they work correctly for equal-always?, chaperone-of?, and impersonator-of?.

Due to the differences between these operations, avoid calling equal? within them. Instead, use the third argument to “recur” on the pieces, which allows equal?/recur to work properly, lets the other operations behave in their own distinct ways on the pieces, and enables some cycle detection.

good

(define (equal-proc self other rec)
  (rec (fish-size self) (fish-size other)))

bad

(define (equal-proc self other rec)
  (equal? (fish-size self) (fish-size other)))

Don’t use the third argument to “recur” on counts of elements. When a data structure cares about discrete numbers, it can use = on those, not equal? or “recur”. Using “recur” on counts is bad when a “recur” argument from equal?/recur is too tolerant on numbers within some range of each other.

good

(define (equal-proc self other rec)
  (and (= (tuple-length self) (tuple-length other))
       (for/and ([i (in-range (tuple-length self))])
         (rec ((tuple-getter self) i)
              ((tuple-getter other) i)))))

bad

(define (equal-proc self other rec)
  (and (rec (tuple-length self) (tuple-length other))
       (for/and ([i (in-range (tuple-length self))])
         (rec ((tuple-getter self) i)
              ((tuple-getter other) i)))))

The operations equal? and equal-always? should be symmetric, so equal-proc instances should not change their answer when the arguments swap:

good

(define (equal-proc self other rec)
  (rec (fish-size self) (fish-size other)))

bad

(define (equal-proc self other rec)
  (<= (fish-size self) (fish-size other)))

However, the operations chaperone-of? and impersonator-of? are not symmetric, so when calling the third argument to “recur” on pieces, pass the pieces in the same order they came in:

good

(define (equal-proc self other rec)
  (rec (fish-size self) (fish-size other)))

bad

(define (equal-proc self other rec)
  (rec (fish-size other) (fish-size self)))

The operations equal-always? and chaperone-of? shouldn’t change on mutation, so equal-proc instances should not access potentially-mutable data. This includes avoiding string=?, since strings can be mutable. Type-specific equality functions for immutable types, such as symbol=?, are fine.

fine

(define (equal-proc self other rec)
  ; symbols are immutable: no problem
  (symbol=? (thing-name self) (thing-name other)))

bad

(define (equal-proc self other rec)
  ; strings can be mutable: accesses mutable data
  (string=? (thing-name self) (thing-name other)))

Declaring a struct as mutable makes equal-always? and chaperone-of? avoid using equal-proc, so equal-proc instances are free to access mutable data if the struct is declared mutable:

good

(struct mcell (value) #:mutable
  #:methods gen:equal+hash
  [(define (equal-proc self other rec)
     (rec (mcell-value self)
          (mcell-value other)))
   (define (hash-proc self rec)
     (+ (eq-hash-code struct:mcell)
        (rec (mcell-value self))))
   (define (hash2-proc self rec)
     (+ (eq-hash-code struct:mcell)
        (rec (mcell-value self))))])

bad

(struct mcell (box)
  ; not declared mutable,
  ; but represents mutable data anyway
  #:methods gen:equal+hash
  [(define (equal-proc self other rec)
     (rec (unbox (mcell-box self))
          (unbox (mcell-box other))))
   (define (hash-proc self rec)
     (+ (eq-hash-code struct:mcell)
        (rec (unbox (mcell-value self)))))
   (define (hash2-proc self rec)
     (+ (eq-hash-code struct:mcell)
        (rec (unbox (mcell-value self)))))])

Another way for a struct to control access to mutable data is by implementing gen:equal-mode+hash instead of gen:equal+hash. When the mode is true, equal-mode-proc instances are free to access mutable data, and when the mode is false, they shouldn’t:

also good

(struct mcell (value) #:mutable
  ; only accesses mutable data when mode is true
  #:methods gen:equal-mode+hash
  [(define (equal-mode-proc self other rec mode)
     (and mode
          (rec (mcell-value self)
               (mcell-value other))))
   (define (hash-mode-proc self rec mode)
     (if mode
         (+ (eq-hash-code struct:mcell)
            (rec (mcell-value self)))
         (eq-hash-code self)))])

still bad

(struct mcell (value) #:mutable
  ; accesses mutable data ignoring mode
  #:methods gen:equal-mode+hash
  [(define (equal-mode-proc self other rec mode)
     (rec (mcell-value self)
          (mcell-value other)))
   (define (hash-mode-proc self rec mode)
     (+ (eq-hash-code struct:mcell)
        (rec (mcell-value self))))])

4.1.5 Combining Hash Codes

The bindings documented in this section are provided by the racket/hash-code library, not racket/base or racket.

Added in version 8.8.0.5 of package base.

procedure

(hash-code-combine hc ...)  fixnum?

  hc : exact-integer?
Combines the hcs into a hash code that depends on the order of the inputs. Useful for combining the hash codes of different fields in a structure.

Examples:
> (require racket/hash-code)
> (struct ordered-triple (fst snd thd)
    #:methods gen:equal+hash
    [(define (equal-proc self other rec)
       (and (rec (ordered-triple-fst self) (ordered-triple-fst other))
            (rec (ordered-triple-snd self) (ordered-triple-snd other))
            (rec (ordered-triple-thd self) (ordered-triple-thd other))))
     (define (hash-proc self rec)
       (hash-code-combine (eq-hash-code struct:ordered-triple)
                          (rec (ordered-triple-fst self))
                          (rec (ordered-triple-snd self))
                          (rec (ordered-triple-thd self))))
     (define (hash2-proc self rec)
       (hash-code-combine (eq-hash-code struct:ordered-triple)
                          (rec (ordered-triple-fst self))
                          (rec (ordered-triple-snd self))
                          (rec (ordered-triple-thd self))))])
> (equal? (ordered-triple 'A 'B 'C) (ordered-triple 'A 'B 'C))

#t

> (= (equal-hash-code (ordered-triple 'A 'B 'C))
     (equal-hash-code (ordered-triple 'A 'B 'C)))

#t

> (equal? (ordered-triple 'A 'B 'C) (ordered-triple 'C 'B 'A))

#f

> (= (equal-hash-code (ordered-triple 'A 'B 'C))
     (equal-hash-code (ordered-triple 'C 'B 'A)))

#f

> (equal? (ordered-triple 'A 'B 'C) (ordered-triple 'C 'A 'B))

#f

> (= (equal-hash-code (ordered-triple 'A 'B 'C))
     (equal-hash-code (ordered-triple 'C 'A 'B)))

#f

With one argument, (hash-code-combine hc) mixes the hash code so that it isn’t just hc.

Examples:
> (require racket/hash-code)
> (struct wrap (value)
    #:methods gen:equal+hash
    [(define (equal-proc self other rec)
       (rec (wrap-value self) (wrap-value other)))
     (define (hash-proc self rec)
       ; demonstrates `hash-code-combine` with only one argument
       ; but it's good to combine `(eq-hash-code struct:wrap)` too
       (hash-code-combine (rec (wrap-value self))))
     (define (hash2-proc self rec)
       (hash-code-combine (rec (wrap-value self))))])
> (equal? (wrap 'A) (wrap 'A))

#t

> (= (equal-hash-code (wrap 'A))
     (equal-hash-code (wrap 'A)))

#t

> (equal? (wrap 'A) 'A)

#f

> (= (equal-hash-code (wrap 'A))
     (equal-hash-code 'A))

#f

procedure

(hash-code-combine-unordered hc ...)  fixnum?

  hc : exact-integer?
Combines the hcs into a hash code that does not depend on the order of the inputs. Useful for combining the hash codes of elements of an unordered set.

Examples:
> (require racket/hash-code)
> (struct flip-triple (left mid right)
    #:methods gen:equal+hash
    [(define (equal-proc self other rec)
       (and (rec (flip-triple-mid self) (flip-triple-mid other))
            (or
             (and (rec (flip-triple-left self) (flip-triple-left other))
                  (rec (flip-triple-right self) (flip-triple-right other)))
             (and (rec (flip-triple-left self) (flip-triple-right other))
                  (rec (flip-triple-right self) (flip-triple-left other))))))
     (define (hash-proc self rec)
       (hash-code-combine (eq-hash-code struct:flip-triple)
                          (rec (flip-triple-mid self))
                          (hash-code-combine-unordered
                           (rec (flip-triple-left self))
                           (rec (flip-triple-right self)))))
     (define (hash2-proc self rec)
       (hash-code-combine (eq-hash-code struct:flip-triple)
                          (rec (flip-triple-mid self))
                          (hash-code-combine-unordered
                           (rec (flip-triple-left self))
                           (rec (flip-triple-right self)))))])
> (equal? (flip-triple 'A 'B 'C) (flip-triple 'A 'B 'C))

#t

> (= (equal-hash-code (flip-triple 'A 'B 'C))
     (equal-hash-code (flip-triple 'A 'B 'C)))

#t

> (equal? (flip-triple 'A 'B 'C) (flip-triple 'C 'B 'A))

#t

> (= (equal-hash-code (flip-triple 'A 'B 'C))
     (equal-hash-code (flip-triple 'C 'B 'A)))

#t

> (equal? (flip-triple 'A 'B 'C) (flip-triple 'C 'A 'B))

#f

> (= (equal-hash-code (flip-triple 'A 'B 'C))
     (equal-hash-code (flip-triple 'C 'A 'B)))

#f

> (struct rotate-triple (rock paper scissors)
    #:methods gen:equal+hash
    [(define (equal-proc self other rec)
       (or
        (and (rec (rotate-triple-rock self) (rotate-triple-rock other))
             (rec (rotate-triple-paper self) (rotate-triple-paper other))
             (rec (rotate-triple-scissors self) (rotate-triple-scissors other)))
        (and (rec (rotate-triple-rock self) (rotate-triple-paper other))
             (rec (rotate-triple-paper self) (rotate-triple-scissors other))
             (rec (rotate-triple-scissors self) (rotate-triple-rock other)))
        (and (rec (rotate-triple-rock self) (rotate-triple-scissors other))
             (rec (rotate-triple-paper self) (rotate-triple-rock other))
             (rec (rotate-triple-scissors self) (rotate-triple-paper other)))))
     (define (hash-proc self rec)
       (define r (rec (rotate-triple-rock self)))
       (define p (rec (rotate-triple-paper self)))
       (define s (rec (rotate-triple-scissors self)))
       (hash-code-combine
        (eq-hash-code struct:rotate-triple)
        (hash-code-combine-unordered
         (hash-code-combine r p)
         (hash-code-combine p s)
         (hash-code-combine s r))))
     (define (hash2-proc self rec)
       (define r (rec (rotate-triple-rock self)))
       (define p (rec (rotate-triple-paper self)))
       (define s (rec (rotate-triple-scissors self)))
       (hash-code-combine
        (eq-hash-code struct:rotate-triple)
        (hash-code-combine-unordered
         (hash-code-combine r p)
         (hash-code-combine p s)
         (hash-code-combine s r))))])
> (equal? (rotate-triple 'A 'B 'C) (rotate-triple 'A 'B 'C))

#t

> (= (equal-hash-code (rotate-triple 'A 'B 'C))
     (equal-hash-code (rotate-triple 'A 'B 'C)))

#t

> (equal? (rotate-triple 'A 'B 'C) (rotate-triple 'C 'B 'A))

#f

> (= (equal-hash-code (rotate-triple 'A 'B 'C))
     (equal-hash-code (rotate-triple 'C 'B 'A)))

#f

> (equal? (rotate-triple 'A 'B 'C) (rotate-triple 'C 'A 'B))

#t

> (= (equal-hash-code (rotate-triple 'A 'B 'C))
     (equal-hash-code (rotate-triple 'C 'A 'B)))

#t

procedure

(hash-code-combine* hc ... hcs)  fixnum?

  hc : exact-integer?
  hcs : (listof exact-integer?)
Like hash-code-combine, but the last argument is used as a list of arguments for hash-code-combine, so (hash-code-combine* hc ... hcs) is the same as (apply hash-code-combine hc ... hcs). In other words, the relationship between hash-code-combine and hash-code-combine* is similar to the one between list and list*.

procedure

(hash-code-combine-unordered* hc ... hcs)  fixnum?

  hc : exact-integer?
  hcs : (listof exact-integer?)
Like hash-code-combine-unordered, but the last argument is used as a list of arguments for hash-code-combine-unordered, so (hash-code-combine-unordered* hc ... hcs) is the same as (apply hash-code-combine-unordered hc ... hcs). In other words, the relationship between hash-code-combine-unordered and hash-code-combine-unordered* is similar to the one between list and list*.