Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

4.18 Dictionaries🔗ℹ

A dictionary is an instance of a datatype that maps keys to values. The following datatypes are all dictionaries:

When list of pairs is used as association list but does not have distinct keys (so it’s not an association list), operations like dict-ref and dict-remove operate on the first instance of the key, while operations like dict-map and dict-keys produce an element for every instance of the key.

 (require racket/dict) package: base
The bindings documented in this section are provided by the racket/dict and racket libraries, but not racket/base.

4.18.1 Dictionary Predicates and Contracts🔗ℹ

procedure

(dict? v)  boolean?

  v : any/c
Returns #t if v is a dictionary, #f otherwise.

Beware that dict? is not a constant-time test on pairs, since checking that v is an association list may require traversing the list.

Examples:
> (dict? #hash((a . "apple")))

#t

> (dict? '#("apple" "banana"))

#t

> (dict? '("apple" "banana"))

#f

> (dict? '((a . "apple") (b . "banana")))

#t

procedure

(dict-implements? d sym ...)  boolean?

  d : dict?
  sym : symbol?
Returns #t if d implements all of the methods from gen:dict named by the syms; returns #f otherwise. Fallback implementations do not affect the result; d may support the given methods via fallback implementations yet produce #f.

Examples:
> (dict-implements? (hash 'a "apple") 'dict-set!)

#f

> (dict-implements? (make-hash '((a . "apple") (b . "banana"))) 'dict-set!)

#t

> (dict-implements? (make-hash '((b . "banana") (a . "apple"))) 'dict-remove!)

#t

> (dict-implements? (vector "apple" "banana") 'dict-set!)

#t

> (dict-implements? (vector 'a 'b) 'dict-remove!)

#f

> (dict-implements? (vector 'a "apple") 'dict-set! 'dict-remove!)

#f

procedure

(dict-implements/c sym ...)  flat-contract?

  sym : symbol?
Recognizes dictionaries that support all of the methods from gen:dict named by the syms. Note that the generated contract is not similar to hash/c, but closer to dict-implements?.

Examples:
> (struct deformed-dict ()
    #:methods gen:dict [])
> (define/contract good-dict
    (dict-implements/c)
    (deformed-dict))
> (define/contract bad-dict
    (dict-implements/c 'dict-ref)
    (deformed-dict))

bad-dict: broke its own contract

  promised: (dict-implements/c dict-ref)

  produced: #<deformed-dict>

  in: (dict-implements/c dict-ref)

  contract from: (definition bad-dict)

  blaming: (definition bad-dict)

   (assuming the contract is correct)

  at: eval:14:0

procedure

(dict-mutable? d)  boolean?

  d : dict?
Returns #t if d is mutable via dict-set!, #f otherwise.

Equivalent to (dict-implements? d 'dict-set!).

Examples:
> (dict-mutable? #hash((a . "apple")))

#f

> (dict-mutable? (make-hash))

#t

> (dict-mutable? '#("apple" "banana"))

#f

> (dict-mutable? (vector "apple" "banana"))

#t

> (dict-mutable? '((a . "apple") (b . "banana")))

#f

procedure

(dict-can-remove-keys? d)  boolean?

  d : dict?
Returns #t if d supports removing mappings via dict-remove! and/or dict-remove, #f otherwise.

Equivalent to (or (dict-implements? d 'dict-remove!) (dict-implements? d 'dict-remove)).

Examples:
> (dict-can-remove-keys? #hash((a . "apple")))

#t

> (dict-can-remove-keys? '#("apple" "banana"))

#f

> (dict-can-remove-keys? '((a . "apple") (b . "banana")))

#t

procedure

(dict-can-functional-set? d)  boolean?

  d : dict?
Returns #t if d supports functional update via dict-set, #f otherwise.

Equivalent to (dict-implements? d 'dict-set).

Examples:
> (dict-can-functional-set? #hash((a . "apple")))

#t

> (dict-can-functional-set? (make-hash))

#f

> (dict-can-functional-set? '#("apple" "banana"))

#f

> (dict-can-functional-set? '((a . "apple") (b . "banana")))

#t

4.18.2 Generic Dictionary Interface🔗ℹ

syntax

gen:dict

A generic interface (see Generic Interfaces) that supplies dictionary method implementations for a structure type via the #:methods option of struct definitions. This interface can be used to implement any of the methods documented as Primitive Dictionary Methods and Derived Dictionary Methods.

Examples:
> (struct alist (v)
    #:methods gen:dict
    [(define (dict-ref dict key
                       [default (lambda () (error "key not found" key))])
       (cond [(assoc key (alist-v dict)) => cdr]
             [else (if (procedure? default) (default) default)]))
     (define (dict-set dict key val)
       (alist (cons (cons key val) (alist-v dict))))
     (define (dict-remove dict key)
       (define al (alist-v dict))
       (alist (remove* (filter (λ (p) (equal? (car p) key)) al) al)))
     (define (dict-count dict)
       (length (remove-duplicates (alist-v dict) #:key car)))])
; etc. other methods
> (define d1 (alist '((1 . a) (2 . b))))
> (dict? d1)

#t

> (dict-ref d1 1)

'a

> (dict-remove d1 1)

#<alist>

A structure type property used to define custom extensions to the dictionary API. Using the prop:dict property is discouraged; use the gen:dict generic interface instead. Accepts a vector of 10 method implementations:

4.18.2.1 Primitive Dictionary Methods🔗ℹ

These methods of gen:dict have no fallback implementations; they are only supported for dictionary types that directly implement them.

procedure

(dict-ref dict key [failure-result])  any

  dict : dict?
  key : any/c
  failure-result : failure-result/c
   = (lambda () (raise (make-exn:fail ....)))
Returns the value for key in dict. If no value is found for key, then failure-result determines the result:

  • If failure-result is a procedure, it is called (through a tail call) with no arguments to produce the result.

  • Otherwise, failure-result is returned as the result.

Examples:
> (dict-ref #hash((a . "apple") (b . "beer")) 'a)

"apple"

> (dict-ref #hash((a . "apple") (b . "beer")) 'c)

hash-ref: no value found for key

  key: 'c

> (dict-ref #hash((a . "apple") (b . "beer")) 'c #f)

#f

> (dict-ref '((a . "apple") (b . "banana")) 'b)

"banana"

> (dict-ref #("apple" "banana") 1)

"banana"

> (dict-ref #("apple" "banana") 3 #f)

#f

> (dict-ref #("apple" "banana") -3 #f)

dict-ref: contract violation

  expected: natural?

  given: -3

  in: the k argument of

      (->i

       ((d dict?) (k (d) (dict-key-contract d)))

       ((default any/c))

       any)

  contract from: <collects>/racket/dict.rkt

  blaming: top-level

   (assuming the contract is correct)

  at: <collects>/racket/dict.rkt:182:2

procedure

(dict-set! dict key v)  void?

  dict : (and/c dict? (not/c immutable?))
  key : any/c
  v : any/c
Maps key to v in dict, overwriting any existing mapping for key. The update can fail with a exn:fail:contract exception if dict is not mutable or if key is not an allowed key for the dictionary (e.g., not an exact integer in the appropriate range when dict is a vector).

Examples:
> (define h (make-hash))
> (dict-set! h 'a "apple")
> h

'#hash((a . "apple"))

> (define v (vector #f #f #f))
> (dict-set! v 0 "apple")
> v

'#("apple" #f #f)

procedure

(dict-set dict key v)  (and/c dict? immutable?)

  dict : (and/c dict? immutable?)
  key : any/c
  v : any/c
Functionally extends dict by mapping key to v, overwriting any existing mapping for key, and returning an extended dictionary. The update can fail with a exn:fail:contract exception if dict does not support functional extension or if key is not an allowed key for the dictionary.

Examples:
> (dict-set #hash() 'a "apple")

'#hash((a . "apple"))

> (dict-set #hash((a . "apple") (b . "beer")) 'b "banana")

'#hash((a . "apple") (b . "banana"))

> (dict-set '() 'a "apple")

'((a . "apple"))

> (dict-set '((a . "apple") (b . "beer")) 'b "banana")

'((a . "apple") (b . "banana"))

procedure

(dict-remove! dict key)  void?

  dict : (and/c dict? (not/c immutable?))
  key : any/c
Removes any existing mapping for key in dict. The update can fail if dict is not mutable or does not support removing keys (as is the case for vectors, for example).

Examples:
> (define h (make-hash))
> (dict-set! h 'a "apple")
> h

'#hash((a . "apple"))

> (dict-remove! h 'a)
> h

'#hash()

procedure

(dict-remove dict key)  (and/c dict? immutable?)

  dict : (and/c dict? immutable?)
  key : any/c
Functionally removes any existing mapping for key in dict, returning the fresh dictionary. The update can fail if dict does not support functional update or does not support removing keys.

Examples:
> (define h #hash())
> (define h (dict-set h 'a "apple"))
> h

'#hash((a . "apple"))

> (dict-remove h 'a)

'#hash()

> h

'#hash((a . "apple"))

> (dict-remove h 'z)

'#hash((a . "apple"))

> (dict-remove '((a . "apple") (b . "banana")) 'a)

'((b . "banana"))

procedure

(dict-iterate-first dict)  any/c

  dict : dict?
Returns #f if dict contains no elements, otherwise it returns a non-#f value that is an index to the first element in the dict table; “first” refers to an unspecified ordering of the dictionary elements. For a mutable dict, this index is guaranteed to refer to the first item only as long as no mappings are added to or removed from dict.

Examples:
> (dict-iterate-first #hash((a . "apple") (b . "banana")))

0

> (dict-iterate-first #hash())

#f

> (dict-iterate-first #("apple" "banana"))

0

> (dict-iterate-first '((a . "apple") (b . "banana")))

#<assoc-iter>

procedure

(dict-iterate-next dict pos)  any/c

  dict : dict?
  pos : any/c
Returns either a non-#f that is an index to the element in dict after the element indexed by pos or #f if pos refers to the last element in dict. If pos is not a valid index, then the exn:fail:contract exception is raised. For a mutable dict, the result index is guaranteed to refer to its item only as long as no items are added to or removed from dict. The dict-iterate-next operation should take constant time.

Examples:
> (define h #hash((a . "apple") (b . "banana")))
> (define i (dict-iterate-first h))
> i

0

> (dict-iterate-next h i)

1

> (dict-iterate-next h (dict-iterate-next h i))

#f

procedure

(dict-iterate-key dict pos)  any

  dict : dict?
  pos : any/c
Returns the key for the element in dict at index pos. If pos is not a valid index for dict, the exn:fail:contract exception is raised. The dict-iterate-key operation should take constant time.

Examples:
> (define h '((a . "apple") (b . "banana")))
> (define i (dict-iterate-first h))
> (dict-iterate-key h i)

'a

> (dict-iterate-key h (dict-iterate-next h i))

'b

procedure

(dict-iterate-value dict pos)  any

  dict : dict?
  pos : any/c
Returns the value for the element in dict at index pos. If pos is not a valid index for dict, the exn:fail:contract exception is raised. The dict-iterate-key operation should take constant time.

Examples:
> (define h '((a . "apple") (b . "banana")))
> (define i (dict-iterate-first h))
> (dict-iterate-value h i)

"apple"

> (dict-iterate-value h (dict-iterate-next h i))

"banana"

4.18.2.2 Derived Dictionary Methods🔗ℹ

These methods of gen:dict have fallback implementations in terms of the other methods; they may be supported even by dictionary types that do not directly implement them.

procedure

(dict-has-key? dict key)  boolean?

  dict : dict?
  key : any/c
Returns #t if dict contains a value for the given key, #f otherwise.

Supported for any dict that implements dict-ref.

Examples:
> (dict-has-key? #hash((a . "apple") (b . "beer")) 'a)

#t

> (dict-has-key? #hash((a . "apple") (b . "beer")) 'c)

#f

> (dict-has-key? '((a . "apple") (b . "banana")) 'b)

#t

> (dict-has-key? #("apple" "banana") 1)

#t

> (dict-has-key? #("apple" "banana") 3)

#f

> (dict-has-key? #("apple" "banana") -3)

#f

procedure

(dict-set*! dict key v ... ...)  void?

  dict : (and/c dict? (not/c immutable?))
  key : any/c
  v : any/c
Maps each key to each v in dict, overwriting any existing mapping for each key. The update can fail with a exn:fail:contract exception if dict is not mutable or if any key is not an allowed key for the dictionary (e.g., not an exact integer in the appropriate range when dict is a vector). The update takes place from the left, so later mappings overwrite earlier mappings.

Supported for any dict that implements dict-set!.

Examples:
> (define h (make-hash))
> (dict-set*! h 'a "apple" 'b "banana")
> h

'#hash((a . "apple") (b . "banana"))

> (define v1 (vector #f #f #f))
> (dict-set*! v1 0 "apple" 1 "banana")
> v1

'#("apple" "banana" #f)

> (define v2 (vector #f #f #f))
> (dict-set*! v2 0 "apple" 0 "banana")
> v2

'#("banana" #f #f)

procedure

(dict-set* dict key v ... ...)  (and/c dict? immutable?)

  dict : (and/c dict? immutable?)
  key : any/c
  v : any/c
Functionally extends dict by mapping each key to each v, overwriting any existing mapping for each key, and returning an extended dictionary. The update can fail with a exn:fail:contract exception if dict does not support functional extension or if any key is not an allowed key for the dictionary. The update takes place from the left, so later mappings overwrite earlier mappings.

Supported for any dict that implements dict-set.

Examples:
> (dict-set* #hash() 'a "apple" 'b "beer")

'#hash((a . "apple") (b . "beer"))

> (dict-set* #hash((a . "apple") (b . "beer")) 'b "banana" 'a "anchor")

'#hash((a . "anchor") (b . "banana"))

> (dict-set* '() 'a "apple" 'b "beer")

'((a . "apple") (b . "beer"))

> (dict-set* '((a . "apple") (b . "beer")) 'b "banana" 'a "anchor")

'((a . "anchor") (b . "banana"))

> (dict-set* '((a . "apple") (b . "beer")) 'b "banana" 'b "ballistic")

'((a . "apple") (b . "ballistic"))

procedure

(dict-ref! dict key to-set)  any

  dict : dict?
  key : any/c
  to-set : any/c
Returns the value for key in dict. If no value is found for key, then to-set determines the result as in dict-ref (i.e., it is either a thunk that computes a value or a plain value), and this result is stored in dict for the key. (Note that if to-set is a thunk, it is not invoked in tail position.)

Supported for any dict that implements dict-ref and dict-set!.

Examples:
> (dict-ref! (make-hasheq '((a . "apple") (b . "beer"))) 'a #f)

"apple"

> (dict-ref! (make-hasheq '((a . "apple") (b . "beer"))) 'c 'cabbage)

'cabbage

> (define h (make-hasheq '((a . "apple") (b . "beer"))))
> (dict-ref h 'c)

hash-ref: no value found for key

  key: 'c

> (dict-ref! h 'c (λ () 'cabbage))

'cabbage

> (dict-ref h 'c)

'cabbage

procedure

(dict-update! dict    
  key    
  updater    
  [failure-result])  void?
  dict : (and/c dict? (not/c immutable?))
  key : any/c
  updater : (any/c . -> . any/c)
  failure-result : failure-result/c
   = (lambda () (raise (make-exn:fail ....)))
Composes dict-ref and dict-set! to update an existing mapping in dict, where the optional failure-result argument is used as in dict-ref when no mapping exists for key already.

Supported for any dict that implements dict-ref and dict-set!.

Examples:
> (define h (make-hash))
> (dict-update! h 'a add1)

hash-update!: no value found for key: 'a

> (dict-update! h 'a add1 0)
> h

'#hash((a . 1))

> (define v (vector #f #f #f))
> (dict-update! v 0 not)
> v

'#(#t #f #f)

procedure

(dict-update dict key updater [failure-result])

  (and/c dict? immutable?)
  dict : dict?
  key : any/c
  updater : (any/c . -> . any/c)
  failure-result : failure-result/c
   = (lambda () (raise (make-exn:fail ....)))
Composes dict-ref and dict-set to functionally update an existing mapping in dict, where the optional failure-result argument is used as in dict-ref when no mapping exists for key already.

Supported for any dict that implements dict-ref and dict-set.

Examples:
> (dict-update #hash() 'a add1)

hash-update: no value found for key: 'a

> (dict-update #hash() 'a add1 0)

'#hash((a . 1))

> (dict-update #hash((a . "apple") (b . "beer")) 'b string-length)

'#hash((a . "apple") (b . 4))

procedure

(dict-map dict proc)  (listof any/c)

  dict : dict?
  proc : (any/c any/c . -> . any/c)
Applies the procedure proc to each element in dict in an unspecified order, accumulating the results into a list. The procedure proc is called each time with a key and its value.

Supported for any dict that implements dict-iterate-first, dict-iterate-next, dict-iterate-key, and dict-iterate-value.

Example:
> (dict-map #hash((a . "apple") (b . "banana")) vector)

'(#(b "banana") #(a "apple"))

procedure

(dict-map/copy dict proc)  dict?

  dict : dict?
  proc : (any/c any/c . -> . (values any/c any/c))
Applies the procedure proc to each element in dict in an unspecified order, accumulating the results into a dict of the same kind. The procedure proc is called each time with a key and its value, and must return a corresponding key and value.

Supported for any dict that implements dict-iterate-first, dict-iterate-next, dict-iterate-key, and dict-iterate-value, and either dict-set and dict-clear, or dict-set!, dict-copy, and dict-clear!.

Example:
> (dict-map/copy #hash((a . "apple") (b . "banana")) (lambda (k v) (values k (string-upcase v))))

'#hash((a . "APPLE") (b . "BANANA"))

Added in version 8.5.0.2 of package base.

procedure

(dict-for-each dict proc)  void?

  dict : dict?
  proc : (any/c any/c . -> . any)
Applies proc to each element in dict (for the side-effects of proc) in an unspecified order. The procedure proc is called each time with a key and its value.

Supported for any dict that implements dict-iterate-first, dict-iterate-next, dict-iterate-key, and dict-iterate-value.

Example:
> (dict-for-each #hash((a . "apple") (b . "banana"))
                 (lambda (k v)
                   (printf "~a = ~s\n" k v)))

b = "banana"

a = "apple"

procedure

(dict-empty? dict)  boolean?

  dict : dict?
Reports whether dict is empty.

Supported for any dict that implements dict-iterate-first.

Examples:
> (dict-empty? #hash((a . "apple") (b . "banana")))

#f

> (dict-empty? (vector))

#t

procedure

(dict-count dict)  exact-nonnegative-integer?

  dict : dict?
Returns the number of keys mapped by dict, usually in constant time.

Supported for any dict that implements dict-iterate-first and dict-iterate-next.

Examples:
> (dict-count #hash((a . "apple") (b . "banana")))

2

> (dict-count #("apple" "banana"))

2

procedure

(dict-copy dict)  dict?

  dict : dict?
Produces a new, mutable dictionary of the same type as dict and with the same key/value associations.

Supported for any dict that implements dict-clear, dict-set!, dict-iterate-first, dict-iterate-next, dict-iterate-key, and dict-iterate-value.

Examples:
> (define original (vector "apple" "banana"))
> (define copy (dict-copy original))
> original

'#("apple" "banana")

> copy

'#("apple" "banana")

> (dict-set! copy 1 "carrot")
> original

'#("apple" "banana")

> copy

'#("apple" "carrot")

procedure

(dict-clear dict)  dict?

  dict : dict?
Produces an empty dictionary of the same type as dict. If dict is mutable, the result must be a new dictionary.

Supported for any dict that supports dict-remove, dict-iterate-first, dict-iterate-next, and dict-iterate-key.

Examples:
> (dict-clear #hash((a . "apple") ("banana" . b)))

'#hash()

> (dict-clear '((1 . two) (three . "four")))

'()

procedure

(dict-clear! dict)  void?

  dict : dict?
Removes all of the key/value associations in dict.

Supported for any dict that supports dict-remove!, dict-iterate-first, and dict-iterate-key.

Examples:
> (define table (make-hash))
> (dict-set! table 'a "apple")
> (dict-set! table "banana" 'b)
> table

'#hash((a . "apple") ("banana" . b))

> (dict-clear! table)
> table

'#hash()

procedure

(dict-keys dict)  list?

  dict : dict?
Returns a list of the keys from dict in an unspecified order.

Supported for any dict that implements dict-iterate-first, dict-iterate-next, and dict-iterate-key.

Examples:
> (define h #hash((a . "apple") (b . "banana")))
> (dict-keys h)

'(b a)

procedure

(dict-values dict)  list?

  dict : dict?
Returns a list of the values from dict in an unspecified order.

Supported for any dict that implements dict-iterate-first, dict-iterate-next, and dict-iterate-value.

Examples:
> (define h #hash((a . "apple") (b . "banana")))
> (dict-values h)

'("banana" "apple")

procedure

(dict->list dict)  list?

  dict : dict?
Returns a list of the associations from dict in an unspecified order.

Supported for any dict that implements dict-iterate-first, dict-iterate-next, dict-iterate-key, and dict-iterate-value.

Examples:
> (define h #hash((a . "apple") (b . "banana")))
> (dict->list h)

'((b . "banana") (a . "apple"))

4.18.3 Dictionary Sequences🔗ℹ

procedure

(in-dict dict)  sequence?

  dict : dict?
Returns a sequence whose each element is two values: a key and corresponding value from dict.

Supported for any dict that implements dict-iterate-first, dict-iterate-next, dict-iterate-key, and dict-iterate-value.

Examples:
> (define h #hash((a . "apple") (b . "banana")))
> (for/list ([(k v) (in-dict h)])
    (format "~a = ~s" k v))

'("b = \"banana\"" "a = \"apple\"")

procedure

(in-dict-keys dict)  sequence?

  dict : dict?
Returns a sequence whose elements are the keys of dict.

Supported for any dict that implements dict-iterate-first, dict-iterate-next, and dict-iterate-key.

Examples:
> (define h #hash((a . "apple") (b . "banana")))
> (for/list ([k (in-dict-keys h)])
    k)

'(b a)

procedure

(in-dict-values dict)  sequence?

  dict : dict?
Returns a sequence whose elements are the values of dict.

Supported for any dict that implements dict-iterate-first, dict-iterate-next, and dict-iterate-value.

Examples:
> (define h #hash((a . "apple") (b . "banana")))
> (for/list ([v (in-dict-values h)])
    v)

'("banana" "apple")

procedure

(in-dict-pairs dict)  sequence?

  dict : dict?
Returns a sequence whose elements are pairs, each containing a key and its value from dict (as opposed to using in-dict, which gets the key and value as separate values for each element).

Supported for any dict that implements dict-iterate-first, dict-iterate-next, dict-iterate-key, and dict-iterate-value.

Examples:
> (define h #hash((a . "apple") (b . "banana")))
> (for/list ([p (in-dict-pairs h)])
    p)

'((b . "banana") (a . "apple"))

4.18.4 Contracted Dictionaries🔗ℹ

A structure type property for defining dictionaries with contracts. The value associated with prop:dict/contract must be a list of two immutable vectors:

(list dict-vector
      (vector type-key-contract
              type-value-contract
              type-iter-contract
              instance-key-contract
              instance-value-contract
              instance-iter-contract))

The first vector must be a vector of 10 procedures which match the gen:dict generic interface (in addition, it must be an immutable vector). The second vector must contain six elements; each of the first three is a contract for the dictionary type’s keys, values, and positions, respectively. Each of the second three is either #f or a procedure used to extract the contract from a dictionary instance.

procedure

(dict-key-contract d)  contract?

  d : dict?

procedure

(dict-value-contract d)  contract?

  d : dict?

procedure

(dict-iter-contract d)  contract?

  d : dict?
Returns the contract that d imposes on its keys, values, or iterators, respectively, if d implements the prop:dict/contract interface.

4.18.5 Custom Hash Tables🔗ℹ

syntax

(define-custom-hash-types name
                          optional-predicate
                          comparison-expr
                          optional-hash-functions)
 
optional-predicate = 
  | #:key? predicate-expr
     
optional-hash-functions = 
  | hash1-expr
  | hash1-expr hash2-expr
Creates a new dictionary type based on the given comparison comparison-expr, hash functions hash1-expr and hash2-expr, and key predicate predicate-expr; the interfaces for these functions are the same as in make-custom-hash-types. The new dictionary type has three variants: immutable, mutable with strongly-held keys, and mutable with weakly-held keys.

Defines seven names:

  • name? recognizes instances of the new type,

  • immutable-name? recognizes immutable instances of the new type,

  • mutable-name? recognizes mutable instances of the new type with strongly-held keys,

  • weak-name? recognizes mutable instances of the new type with weakly-held keys,

  • make-immutable-name constructs immutable instances of the new type,

  • make-mutable-name constructs mutable instances of the new type with strongly-held keys, and

  • make-weak-name constructs mutable instances of the new type with weakly-held keys.

The constructors all accept a dictionary as an optional argument, providing initial key/value pairs.

Examples:
> (define-custom-hash-types string-hash
                            #:key? string?
                            string=?
                            string-length)
> (define imm
    (make-immutable-string-hash
     '(("apple" . a) ("banana" . b))))
> (define mut
    (make-mutable-string-hash
     '(("apple" . a) ("banana" . b))))
> (dict? imm)

#t

> (dict? mut)

#t

> (string-hash? imm)

#t

> (string-hash? mut)

#t

> (immutable-string-hash? imm)

#t

> (immutable-string-hash? mut)

#f

> (dict-ref imm "apple")

'a

> (dict-ref mut "banana")

'b

> (dict-set! mut "banana" 'berry)
> (dict-ref mut "banana")

'berry

> (equal? imm mut)

#f

> (equal? (dict-remove (dict-remove imm "apple") "banana")
          (make-immutable-string-hash))

#t

procedure

(make-custom-hash-types eql?    
  [hash1    
  hash2    
  #:key? key?    
  #:name name    
  #:for who])  
(any/c . -> . boolean?)
(any/c . -> . boolean?)
(any/c . -> . boolean?)
(any/c . -> . boolean?)
(->* [] [dict?] dict?)
(->* [] [dict?] dict?)
(->* [] [dict?] dict?)
  eql? : 
(or/c (any/c any/c . -> . any/c)
      (any/c any/c (any/c any/c . -> . any/c) . -> . any/c))
  hash1 : 
(or/c (any/c . -> . exact-integer?)
      (any/c (any/c . -> . exact-integer?) . -> . exact-integer?))
   = (const 1)
  hash2 : 
(or/c (any/c . -> . exact-integer?)
      (any/c (any/c . -> . exact-integer?) . -> . exact-integer?))
   = (const 1)
  key? : (any/c . -> . boolean?) = (const #true)
  name : symbol? = 'custom-hash
  who : symbol? = 'make-custom-hash-types
Creates a new dictionary type based on the given comparison function eql?, hash functions hash1 and hash2, and predicate key?. The new dictionary type has variants that are immutable, mutable with strongly-held keys, and mutable with weakly-held keys. The given name is used when printing instances of the new dictionary type, and the symbol who is used for reporting errors.

The comparison function eql? may accept 2 or 3 arguments. If it accepts 2 arguments, it given two keys to compare them. If it accepts 3 arguments and does not accept 2 arguments, it is also given a recursive comparison function that handles data cycles when comparing sub-parts of the keys.

The hash functions hash1 and hash2 may accept 1 or 2 arguments. If either hash function accepts 1 argument, it is applied to a key to compute the corresponding hash value. If either hash function accepts 2 arguments and does not accept 1 argument, it is also given a recursive hash function that handles data cycles when computing hash values of sub-parts of the keys.

The predicate key? must accept 1 argument and is used to recognize valid keys for the new dictionary type.

Produces seven values:

  • a predicate recognizing all instances of the new dictionary type,

  • a predicate recognizing immutable instances,

  • a predicate recognizing mutable instances,

  • a predicate recognizing weak instances,

  • a constructor for immutable instances,

  • a constructor for mutable instances, and

  • a constructor for weak instances.

See define-custom-hash-types for an example.

procedure

(make-custom-hash eql?    
  [hash1    
  hash2    
  #:key? key?])  dict?
  eql? : 
(or/c (any/c any/c . -> . any/c)
      (any/c any/c (any/c any/c . -> . any/c) . -> . any/c))
  hash1 : 
(or/c (any/c . -> . exact-integer?)
      (any/c (any/c . -> . exact-integer?) . -> . exact-integer?))
   = (const 1)
  hash2 : 
(or/c (any/c . -> . exact-integer?)
      (any/c (any/c . -> . exact-integer?) . -> . exact-integer?))
   = (const 1)
  key? : (any/c . -> . boolean?) = (λ (x) #true)

procedure

(make-weak-custom-hash eql?    
  [hash1    
  hash2    
  #:key? key?])  dict?
  eql? : 
(or/c (any/c any/c . -> . any/c)
      (any/c any/c (any/c any/c . -> . any/c) . -> . any/c))
  hash1 : 
(or/c (any/c . -> . exact-integer?)
      (any/c (any/c . -> . exact-integer?) . -> . exact-integer?))
   = (const 1)
  hash2 : 
(or/c (any/c . -> . exact-integer?)
      (any/c (any/c . -> . exact-integer?) . -> . exact-integer?))
   = (const 1)
  key? : (any/c . -> . boolean?) = (λ (x) #true)

procedure

(make-immutable-custom-hash eql?    
  [hash1    
  hash2    
  #:key? key?])  dict?
  eql? : 
(or/c (any/c any/c . -> . any/c)
      (any/c any/c (any/c any/c . -> . any/c) . -> . any/c))
  hash1 : 
(or/c (any/c . -> . exact-integer?)
      (any/c (any/c . -> . exact-integer?) . -> . exact-integer?))
   = (const 1)
  hash2 : 
(or/c (any/c . -> . exact-integer?)
      (any/c (any/c . -> . exact-integer?) . -> . exact-integer?))
   = (const 1)
  key? : (any/c . -> . boolean?) = (λ (x) #true)
Creates an instance of a new dictionary type, implemented in terms of a hash table where keys are compared with eql?, hashed with hash1 and hash2, and where the key predicate is key?. See gen:equal-mode+hash and gen:equal+hash for information on suitable equality and hashing functions.

The make-custom-hash and make-weak-custom-hash functions create a mutable dictionary that does not support functional update, while make-immutable-custom-hash creates an immutable dictionary that supports functional update. The dictionary created by make-weak-custom-hash retains its keys weakly, like the result of make-weak-hash.

Dictionaries created by make-custom-hash and company are equal? when they have the same mutability and key strength, the associated procedures are equal?, and the key–value mappings are the same when keys and values are compared with equal?.

See also define-custom-hash-types.

Examples:
> (define h (make-custom-hash (lambda (a b)
                                (string=? (format "~a" a)
                                          (format "~a" b)))
                              (lambda (a)
                                (equal-hash-code
                                 (format "~a" a)))))
> (dict-set! h 1 'one)
> (dict-ref h "1")

'one

4.18.6 Passing Keyword Arguments in Dictionaries🔗ℹ

procedure

(keyword-apply/dict proc    
  kw-dict    
  pos-arg ...    
  pos-args    
  #:<kw> kw-arg ...)  any
  proc : procedure?
  kw-dict : dict?
  pos-arg : any/c
  pos-args : (listof any/c)
  kw-arg : any/c
Applies the proc using the positional arguments from (list* pos-arg ... pos-args), and the keyword arguments from kw-dict in addition to the directly supplied keyword arguments in the #:<kw> kw-arg sequence.

All the keys in kw-dict must be keywords. The keywords in the kw-dict do not have to be sorted. However, the keywords in kw-dict and the directly supplied #:<kw> keywords must not overlap. The given proc must accept all of the keywords in kw-dict plus the #:<kw>s.

Examples:
> (define (sundae #:ice-cream [ice-cream '("vanilla")]
                  #:toppings [toppings '("brownie-bits")]
                  #:sprinkles [sprinkles "chocolate"]
                  #:syrup [syrup "caramel"])
    (format "A sundae with ~a ice cream, ~a, ~a sprinkles, and ~a syrup."
            (string-join ice-cream #:before-last " and ")
            (string-join toppings #:before-last " and ")
            sprinkles
            syrup))
> (keyword-apply/dict sundae '((#:ice-cream    "chocolate"))  '())

"A sundae with chocolate ice cream, brownie-bits, chocolate sprinkles, and caramel syrup."

> (keyword-apply/dict sundae
                      (hash '#:toppings '("cookie-dough")
                            '#:sprinkles "rainbow"
                            '#:syrup "chocolate")
                      '())

"A sundae with vanilla ice cream, cookie-dough, rainbow sprinkles, and chocolate syrup."

> (keyword-apply/dict sundae
                      #:sprinkles "rainbow"
                      (hash '#:toppings '("cookie-dough")
                            '#:syrup "chocolate")
                      '())

"A sundae with vanilla ice cream, cookie-dough, rainbow sprinkles, and chocolate syrup."

Added in version 7.9 of package base.