You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
typesetting/quad/qtest/mds/data.md

35 KiB

Built-In Datatypes

The previous chapter introduced some of Rackets built-in datatypes: numbers, booleans, strings, lists, and procedures. This section provides a more complete coverage of the built-in datatypes for simple forms of data.

1 Booleans              
                        
2 Numbers               
                        
3 Characters            
                        
4 Strings \(Unicode\)   
                        
5 Bytes and Byte Strings
                        
6 Symbols               
                        
7 Keywords              
                        
8 Pairs and Lists       
                        
9 Vectors               
                        
10 Hash Tables          
                        
11 Boxes                
                        
12 Void and Undefined   

1. Booleans

Racket has two distinguished constants to represent boolean values: #t for true and #f for false. Uppercase #T and #F are parsed as the same values, but the lowercase forms are preferred.

The boolean? procedure recognizes the two boolean constants. In the result of a test expression for if, cond, and, or, etc., however, any value other than #f counts as true.

Examples:

> (= 2 (+ 1 1))  
#t               
> (boolean? #t)  
#t               
> (boolean? #f)  
#t               
> (boolean? "no")
#f               
> (if "no" 1 0)  
1                

2. Numbers

A Racket number is either exact or inexact:

  • An exact number is either

    • an arbitrarily large or small integer, such as 5, 99999999999999999, or -17;

    • a rational that is exactly the ratio of two arbitrarily small or large integers, such as 1/2, 99999999999999999/2, or -3/4; or

    • a complex number with exact real and imaginary parts (where the imaginary part is not zero), such as 1+2i or 1/2+3/4i.

  • An inexact number is either

    • an IEEE floating-point representation of a number, such as 2.0 or 3.14e+87, where the IEEE infinities and not-a-number are written +inf.0, -inf.0, and +nan.0 or `-nan.0`; or

    • a complex number with real and imaginary parts that are IEEE floating-point representations, such as 2.0+3.0i or -inf.0+nan.0i; as a special case, an inexact complex number can have an exact zero real part with an inexact imaginary part.

Inexact numbers print with a decimal point or exponent specifier, and exact numbers print as integers and fractions. The same conventions apply for reading number constants, but #e or #i can prefix a number to force its parsing as an exact or inexact number. The prefixes #b, #o, and #x specify binary, octal, and hexadecimal interpretation of digits.

+[missing] in [missing] documents the fine points of the syntax of numbers.

Examples:

> 0.5   
0.5     
> #e0.5 
1/2     
> #x03BB
955     

Computations that involve an inexact number produce inexact results, so that inexactness acts as a kind of taint on numbers. Beware, however, that Racket offers no “inexact booleans,” so computations that branch on the comparison of inexact numbers can nevertheless produce exact results. The procedures exact->inexact and inexact->exact convert between the two types of numbers.

Examples:

> (/ 1 2)                         
1/2                               
> (/ 1 2.0)                       
0.5                               
> (if (= 3.0 2.999) 1 2)          
2                                 
> (inexact->exact 0.1)            
3602879701896397/36028797018963968

Inexact results are also produced by procedures such as sqrt, log, and sin when an exact result would require representing real numbers that are not rational. Racket can represent only rational numbers and complex numbers with rational parts.

Examples:

> (sin 0)   ; rational...    
0                            
> (sin 1/2) ; not rational...
0.479425538604203            

In terms of performance, computations with small integers are typically the fastest, where “small” means that the number fits into one bit less than the machines word-sized representation for signed numbers. Computation with very large exact integers or with non-integer exact numbers can be much more expensive than computation with inexact numbers.

(define (sigma f a b)                                 
  (if (= a b)                                         
      0                                               
      (+ (f a) (sigma f (+ a 1) b))))                 
> (time (round (sigma (lambda (x) (/ 1 x)) 1 2000)))  
cpu time: 63 real time: 64 gc time: 0                 
8                                                     
> (time (round (sigma (lambda (x) (/ 1.0 x)) 1 2000)))
cpu time: 1 real time: 0 gc time: 0                   
8.0                                                   

The number categories integer, rational, real always rational, and complex are defined in the usual way, and are recognized by the procedures integer?, rational?, real?, and complex?, in addition to the generic number?. A few mathematical procedures accept only real numbers, but most implement standard extensions to complex numbers.

Examples:

> (integer? 5)                        
#t                                    
> (complex? 5)                        
#t                                    
> (integer? 5.0)                      
#t                                    
> (integer? 1+2i)                     
#f                                    
> (complex? 1+2i)                     
#t                                    
> (complex? 1.0+2.0i)                 
#t                                    
> (abs -5)                            
5                                     
> (abs -5+2i)                         
abs: contract violation               
  expected: real?                     
  given: -5+2i                        
> (sin -5+2i)                         
3.6076607742131563+1.0288031496599337i

The = procedure compares numbers for numerical equality. If it is given both inexact and exact numbers to compare, it essentially converts the inexact numbers to exact before comparing. The eqv? (and therefore equal?) procedure, in contrast, compares numbers considering both exactness and numerical equality.

Examples:

> (= 1 1.0)   
#t            
> (eqv? 1 1.0)
#f            

Beware of comparisons involving inexact numbers, which by their nature can have surprising behavior. Even apparently simple inexact numbers may not mean what you think they mean; for example, while a base-2 IEEE floating-point number can represent 1/2 exactly, it can only approximate 1/10:

Examples:

> (= 1/2 0.5)                     
#t                                
> (= 1/10 0.1)                    
#f                                
> (inexact->exact 0.1)            
3602879701896397/36028797018963968

+[missing] in [missing] provides more on numbers and number procedures.

3. Characters

A Racket character corresponds to a Unicode scalar value. Roughly, a scalar value is an unsigned integer whose representation fits into 21 bits, and that maps to some notion of a natural-language character or piece of a character. Technically, a scalar value is a simpler notion than the concept called a “character” in the Unicode standard, but its an approximation that works well for many purposes. For example, any accented Roman letter can be represented as a scalar value, as can any common Chinese character.

Although each Racket character corresponds to an integer, the character datatype is separate from numbers. The char->integer and integer->char procedures convert between scalar-value numbers and the corresponding character.

A printable character normally prints as #\ followed by the represented character. An unprintable character normally prints as #\u followed by the scalar value as hexadecimal number. A few characters are printed specially; for example, the space and linefeed characters print as #\space and #\newline, respectively.

+[missing] in [missing] documents the fine points of the syntax of characters.

Examples:

> (integer->char 65)     
#\A                      
> (char->integer #\A)    
65                       
> #\λ                    
#\λ                      
> #\u03BB                
#\λ                      
> (integer->char 17)     
#\u0011                  
> (char->integer #\space)
32                       

The display procedure directly writes a character to the current output port see \[missing\], in contrast to the character-constant syntax used to print a character result.

Examples:

> #\A          
#\A            
> (display #\A)
A              

Racket provides several classification and conversion procedures on characters. Beware, however, that conversions on some Unicode characters work as a human would expect only when they are in a string (e.g., upcasing “ß” or downcasing “Σ”).

Examples:

> (char-alphabetic? #\A)      
#t                            
> (char-numeric? #\0)         
#t                            
> (char-whitespace? #\newline)
#t                            
> (char-downcase #\A)         
#\a                           
> (char-upcase #\ß)           
#\ß                           

The char=? procedure compares two or more characters, and char-ci=? compares characters ignoring case. The eqv? and equal? procedures behave the same as char=? on characters; use char=? when you want to more specifically declare that the values being compared are characters.

Examples:

> (char=? #\a #\A)   
#f                   
> (char-ci=? #\a #\A)
#t                   
> (eqv? #\a #\A)     
#f                   

+[missing] in [missing] provides more on characters and character procedures.

4. Strings Unicode

A string is a fixed-length array of characters. It prints using doublequotes, where doublequote and backslash characters within the string are escaped with backslashes. Other common string escapes are supported, including \n for a linefeed, \r for a carriage return, octal escapes using \ followed by up to three octal digits, and hexadecimal escapes with \u up to four digits. Unprintable characters in a string are normally shown with \u when the string is printed.

+[missing] in [missing] documents the fine points of the syntax of strings.

The display procedure directly writes the characters of a string to the current output port see \[missing\], in contrast to the string-constant syntax used to print a string result.

Examples:

> "Apple"                       
"Apple"                         
> "\u03BB"                      
"λ"                             
> (display "Apple")             
Apple                           
> (display "a \"quoted\" thing")
a "quoted" thing                
> (display "two\nlines")        
two                             
lines                           
> (display "\u03BB")            
λ                               

A string can be mutable or immutable; strings written directly as expressions are immutable, but most other strings are mutable. The make-string procedure creates a mutable string given a length and optional fill character. The string-ref procedure accesses a character from a string with 0-based indexing; the string-set! procedure changes a character in a mutable string.

Examples:

> (string-ref "Apple" 0)        
#\A                             
> (define s (make-string 5 #\.))
> s                             
"....."                         
> (string-set! s 2 #\λ)         
> s                             
"..λ.."                         

String ordering and case operations are generally locale-independent; that is, they work the same for all users. A few locale-dependent operations are provided that allow the way that strings are case-folded and sorted to depend on the end-users locale. If youre sorting strings, for example, use string<? or string-ci<? if the sort result should be consistent across machines and users, but use string-locale<? or string-locale-ci<? if the sort is purely to order strings for an end user.

Examples:

> (string<? "apple" "Banana")         
#f                                    
> (string-ci<? "apple" "Banana")      
#t                                    
> (string-upcase "Straße")            
"STRASSE"                             
> (parameterize ([current-locale "C"])
    (string-locale-upcase "Straße"))  
"STRAßE"                              

For working with plain ASCII, working with raw bytes, or encoding/decoding Unicode strings as bytes, use byte strings.

+[missing] in [missing] provides more on strings and string procedures.

5. Bytes and Byte Strings

A byte is an exact integer between 0 and 255, inclusive. The byte? predicate recognizes numbers that represent bytes.

Examples:

> (byte? 0)  
#t           
> (byte? 256)
#f           

A byte string is similar to a string—see Strings Unicode—but its content is a sequence of bytes instead of characters. Byte strings can be used in applications that process pure ASCII instead of Unicode text. The printed form of a byte string supports such uses in particular, because a byte string prints like the ASCII decoding of the byte string, but prefixed with a #. Unprintable ASCII characters or non-ASCII bytes in the byte string are written with octal notation.

+[missing] in [missing] documents the fine points of the syntax of byte strings.

Examples:

> #"Apple"                   
#"Apple"                     
> (bytes-ref #"Apple" 0)     
65                           
> (make-bytes 3 65)          
#"AAA"                       
> (define b (make-bytes 2 0))
> b                          
#"\0\0"                      
> (bytes-set! b 0 1)         
> (bytes-set! b 1 255)       
> b                          
#"\1\377"                    

The display form of a byte string writes its raw bytes to the current output port see \[missing\]. Technically, display of a normal i.e,. character string prints the UTF-8 encoding of the string to the current output port, since output is ultimately defined in terms of bytes; display of a byte string, however, writes the raw bytes with no encoding. Along the same lines, when this documentation shows output, it technically shows the UTF-8-decoded form of the output.

Examples:

> (display #"Apple")                         
Apple                                        
> (display "\316\273")  ; same as "λ"       
λ                                           
> (display #"\316\273") ; UTF-8 encoding of λ
λ                                            

For explicitly converting between strings and byte strings, Racket supports three kinds of encodings directly: UTF-8, Latin-1, and the current locales encoding. General facilities for byte-to-byte conversions especially to and from UTF-8 fill the gap to support arbitrary string encodings.

Examples:

> (bytes->string/utf-8 #"\316\273")                               
"λ"                                                               
> (bytes->string/latin-1 #"\316\273")                             
"λ"                                                              
> (parameterize ([current-locale "C"])  ; C locale supports ASCII,
    (bytes->string/locale #"\316\273")) ; only, so...             
bytes->string/locale: byte string is not a valid encoding         
for the current locale                                            
  byte string: #"\316\273"                                        
> (let ([cvt (bytes-open-converter "cp1253" ; Greek code page     
                                   "UTF-8")]                      
        [dest (make-bytes 2)])                                    
    (bytes-convert cvt #"\353" 0 1 dest)                          
    (bytes-close-converter cvt)                                   
    (bytes->string/utf-8 dest))                                   
"λ"                                                               

+[missing] in [missing] provides more on byte strings and byte-string procedures.

6. Symbols

A symbol is an atomic value that prints like an identifier preceded with '. An expression that starts with ' and continues with an identifier produces a symbol value.

Examples:

> 'a          
'a            
> (symbol? 'a)
#t            

For any sequence of characters, exactly one corresponding symbol is interned; calling the string->symbol procedure, or reading a syntactic identifier, produces an interned symbol. Since interned symbols can be cheaply compared with eq? (and thus eqv? or equal?), they serve as a convenient values to use for tags and enumerations.

Symbols are case-sensitive. By using a #ci prefix or in other ways, the reader can be made to case-fold character sequences to arrive at a symbol, but the reader preserves case by default.

Examples:

> (eq? 'a 'a)                  
#t                             
> (eq? 'a (string->symbol "a"))
#t                             
> (eq? 'a 'b)                  
#f                             
> (eq? 'a 'A)                  
#f                             
> #ci'A                        
'a                             

Any string i.e., any character sequence can be supplied to string->symbol to obtain the corresponding symbol. For reader input, any character can appear directly in an identifier, except for whitespace and the following special characters:

   ( ) [ ] { } " , ' ; # | `

Actually, # is disallowed only at the beginning of a symbol, and then only if not followed by %; otherwise, # is allowed, too. Also, . by itself is not a symbol.

Whitespace or special characters can be included in an identifier by quoting them with | or \. These quoting mechanisms are used in the printed form of identifiers that contain special characters or that might otherwise look like numbers.

Examples:

> (string->symbol "one, two")
'|one, two|                  
> (string->symbol "6")       
'|6|                         

+[missing] in [missing] documents the fine points of the syntax of symbols.

The write function prints a symbol without a ' prefix. The display form of a symbol is the same as the corresponding string.

Examples:

> (write 'Apple)  
Apple             
> (display 'Apple)
Apple             
> (write '|6|)    
|6|               
> (display '|6|)  
6                 

The gensym and string->uninterned-symbol procedures generate fresh uninterned symbols that are not equal according to `eq?` to any previously interned or uninterned symbol. Uninterned symbols are useful as fresh tags that cannot be confused with any other value.

Examples:

> (define s (gensym))                     
> s                                       
'g42                                      
> (eq? s 'g42)                            
#f                                        
> (eq? 'a (string->uninterned-symbol "a"))
#f                                        

+[missing] in [missing] provides more on symbols.

7. Keywords

A keyword value is similar to a symbol see Symbols, but its printed form is prefixed with #:.

+[missing] in [missing] documents the fine points of the syntax of keywords.

Examples:

> (string->keyword "apple")               
'#:apple                                  
> '#:apple                                
'#:apple                                  
> (eq? '#:apple (string->keyword "apple"))
#t                                        

More precisely, a keyword is analogous to an identifier; in the same way that an identifier can be quoted to produce a symbol, a keyword can be quoted to produce a value. The same term “keyword” is used in both cases, but we sometimes use keyword value to refer more specifically to the result of a quote-keyword expression or of string->keyword. An unquoted keyword is not an expression, just as an unquoted identifier does not produce a symbol:

Examples:

> not-a-symbol-expression                            
not-a-symbol-expression: undefined;                  
 cannot reference an identifier before its definition
  in module: top-level                               
> #:not-a-keyword-expression                         
eval:2:0: #%datum: keyword misused as an expression  
  at: #:not-a-keyword-expression                     

Despite their similarities, keywords are used in a different way than identifiers or symbols. Keywords are intended for use unquoted as special markers in argument lists and in certain syntactic forms. For run-time flags and enumerations, use symbols instead of keywords. The example below illustrates the distinct roles of keywords and symbols.

Examples:

> (define dir (find-system-path 'temp-dir)) ; not '#:temp-dir   
> (with-output-to-file (build-path dir "stuff.txt")             
    (lambda () (printf "example\n"))                            
    ; optional #:mode argument can be 'text or 'binary          
    #:mode 'text                                                
    ; optional #:exists argument can be 'replace, 'truncate, ...
    #:exists 'replace)                                          

8. Pairs and Lists

A pair joins two arbitrary values. The cons procedure constructs pairs, and the car and cdr procedures extract the first and second elements of the pair, respectively. The pair? predicate recognizes pairs.

Some pairs print by wrapping parentheses around the printed forms of the two pair elements, putting a ' at the beginning and a . between the elements.

Examples:

> (cons 1 2)         
'(1 . 2)             
> (cons (cons 1 2) 3)
'((1 . 2) . 3)       
> (car (cons 1 2))   
1                    
> (cdr (cons 1 2))   
2                    
> (pair? (cons 1 2)) 
#t                   

A list is a combination of pairs that creates a linked list. More precisely, a list is either the empty list null, or it is a pair whose first element is a list element and whose second element is a list. The list? predicate recognizes lists. The null? predicate recognizes the empty list.

A list normally prints as a ' followed by a pair of parentheses wrapped around the list elements.

Examples:

> null                           
'()                              
> (cons 0 (cons 1 (cons 2 null)))
'(0 1 2)                         
> (list? null)                   
#t                               
> (list? (cons 1 (cons 2 null))) 
#t                               
> (list? (cons 1 2))             
#f                               

A list or pair prints using list or cons when one of its elements cannot be written as a quoted value. For example, a value constructed with srcloc cannot be written using quote, and it prints using srcloc:

> (srcloc "file.rkt" 1 0 1 (+ 4 4))              
(srcloc "file.rkt" 1 0 1 8)                      
> (list 'here (srcloc "file.rkt" 1 0 1 8) 'there)
(list 'here (srcloc "file.rkt" 1 0 1 8) 'there)  
> (cons 1 (srcloc "file.rkt" 1 0 1 8))           
(cons 1 (srcloc "file.rkt" 1 0 1 8))             
> (cons 1 (cons 2 (srcloc "file.rkt" 1 0 1 8)))  
(list* 1 2 (srcloc "file.rkt" 1 0 1 8))          

See also list*.

As shown in the last example, list* is used to abbreviate a series of conses that cannot be abbreviated using list.

The write and display functions print a pair or list without a leading ', cons, list, or list*. There is no difference between write and display for a pair or list, except as they apply to elements of the list:

Examples:

> (write (cons 1 2))      
(1 . 2)                   
> (display (cons 1 2))    
(1 . 2)                   
> (write null)            
()                        
> (display null)          
()                        
> (write (list 1 2 "3"))  
(1 2 "3")                 
> (display (list 1 2 "3"))
(1 2 3)                   

Among the most important predefined procedures on lists are those that iterate through the lists elements:

> (map (lambda (i) (/ 1 i))                                
       '(1 2 3))                                           
'(1 1/2 1/3)                                               
> (andmap (lambda (i) (i . < . 3))                         
         '(1 2 3))                                         
#f                                                         
> (ormap (lambda (i) (i . < . 3))                          
         '(1 2 3))                                         
#t                                                         
> (filter (lambda (i) (i . < . 3))                         
          '(1 2 3))                                        
'(1 2)                                                     
> (foldl (lambda (v i) (+ v i))                            
         10                                                
         '(1 2 3))                                         
16                                                         
> (for-each (lambda (i) (display i))                       
            '(1 2 3))                                      
123                                                        
> (member "Keys"                                           
          '("Florida" "Keys" "U.S.A."))                    
'("Keys" "U.S.A.")                                         
> (assoc 'where                                            
         '((when "3:30") (where "Florida") (who "Mickey")))
'(where "Florida")                                         

+[missing] in [missing] provides more on pairs and lists.

Pairs are immutable contrary to Lisp tradition, and pair? and list? recognize immutable pairs and lists, only. The mcons procedure creates a mutable pair, which works with set-mcar! and set-mcdr!, as well as mcar and mcdr. A mutable pair prints using mcons, while write and display print mutable pairs with { and }:

Examples:

> (define p (mcons 1 2))
> p                     
(mcons 1 2)             
> (pair? p)             
#f                      
> (mpair? p)            
#t                      
> (set-mcar! p 0)       
> p                     
(mcons 0 2)             
> (write p)             
{0 . 2}                 

+[missing] in [missing] provides more on mutable pairs.

9. Vectors

A vector is a fixed-length array of arbitrary values. Unlike a list, a vector supports constant-time access and update of its elements.

A vector prints similar to a list—as a parenthesized sequence of its elements—but a vector is prefixed with # after ', or it uses vector if one of its elements cannot be expressed with quote.

For a vector as an expression, an optional length can be supplied. Also, a vector as an expression implicitly quotes the forms for its content, which means that identifiers and parenthesized forms in a vector constant represent symbols and lists.

+[missing] in [missing] documents the fine points of the syntax of vectors.

Examples:

> #("a" "b" "c")                    
'#("a" "b" "c")                     
> #(name (that tune))               
'#(name (that tune))                
> #4(baldwin bruce)                 
'#(baldwin bruce bruce bruce)       
> (vector-ref #("a" "b" "c") 1)     
"b"                                 
> (vector-ref #(name (that tune)) 1)
'(that tune)                        

Like strings, a vector is either mutable or immutable, and vectors written directly as expressions are immutable.

Vectors can be converted to lists and vice versa via vector->list and list->vector; such conversions are particularly useful in combination with predefined procedures on lists. When allocating extra lists seems too expensive, consider using looping forms like for/fold, which recognize vectors as well as lists.

Example:

> (list->vector (map string-titlecase                          
                     (vector->list #("three" "blind" "mice"))))
'#("Three" "Blind" "Mice")                                     

+[missing] in [missing] provides more on vectors and vector procedures.

10. Hash Tables

A hash table implements a mapping from keys to values, where both keys and values can be arbitrary Racket values, and access and update to the table are normally constant-time operations. Keys are compared using equal?, eqv?, or eq?, depending on whether the hash table is created with make-hash, make-hasheqv, or make-hasheq.

Examples:

> (define ht (make-hash))               
> (hash-set! ht "apple" '(red round))   
> (hash-set! ht "banana" '(yellow long))
> (hash-ref ht "apple")                 
'(red round)                            
> (hash-ref ht "coconut")               
hash-ref: no value found for key        
  key: "coconut"                        
> (hash-ref ht "coconut" "not there")   
"not there"                             

The hash, hasheqv, and hasheq functions create immutable hash tables from an initial set of keys and values, in which each value is provided as an argument after its key. Immutable hash tables can be extended with hash-set, which produces a new immutable hash table in constant time.

Examples:

> (define ht (hash "apple" 'red "banana" 'yellow))
> (hash-ref ht "apple")                           
'red                                              
> (define ht2 (hash-set ht "coconut" 'brown))     
> (hash-ref ht "coconut")                         
hash-ref: no value found for key                  
  key: "coconut"                                  
> (hash-ref ht2 "coconut")                        
'brown                                            

A literal immutable hash table can be written as an expression by using #hash for an `equal?`-based table, #hasheqv (for an eqv?-based table), or #hasheq for an `eq?`-based table. A parenthesized sequence must immediately follow #hash, #hasheq, or #hasheqv, where each element is a dotted keyvalue pair. The #hash, etc. forms implicitly quote their key and value sub-forms.

Examples:

> (define ht #hash(("apple" . red)      
                   ("banana" . yellow)))
> (hash-ref ht "apple")                 
'red                                    

+[missing] in [missing] documents the fine points of the syntax of hash table literals.

Both mutable and immutable hash tables print like immutable hash tables, using a quoted #hash, #hasheqv, or #hasheq form if all keys and values can be expressed with quote or using hash, hasheq, or hasheqv otherwise:

Examples:

> #hash(("apple" . red)                     
        ("banana" . yellow))                
'#hash(("banana" . yellow) ("apple" . red)) 
> (hash 1 (srcloc "file.rkt" 1 0 1 (+ 4 4)))
(hash 1 (srcloc "file.rkt" 1 0 1 8))        

A mutable hash table can optionally retain its keys weakly, so each mapping is retained only so long as the key is retained elsewhere.

Examples:

> (define ht (make-weak-hasheq))           
> (hash-set! ht (gensym) "can you see me?")
> (collect-garbage)                        
> (hash-count ht)                          
0                                          

Beware that even a weak hash table retains its values strongly, as long as the corresponding key is accessible. This creates a catch-22 dependency when a value refers back to its key, so that the mapping is retained permanently. To break the cycle, map the key to an ephemeron that pairs the value with its key (in addition to the implicit pairing of the hash table).

+[missing] in [missing] documents the fine points of using ephemerons.

Examples:

> (define ht (make-weak-hasheq))
> (let ([g (gensym)])           
    (hash-set! ht g (list g)))  
> (collect-garbage)             
> (hash-count ht)               
1                               
> (define ht (make-weak-hasheq))                 
> (let ([g (gensym)])                            
    (hash-set! ht g (make-ephemeron g (list g))))
> (collect-garbage)                              
> (hash-count ht)                                
0                                                

+[missing] in [missing] provides more on hash tables and hash-table procedures.

11. Boxes

A box is like a single-element vector. It can print as a quoted #& followed by the printed form of the boxed value. A #& form can also be used as an expression, but since the resulting box is constant, it has practically no use.

Examples:

> (define b (box "apple"))   
> b                          
'#&"apple"                   
> (unbox b)                  
"apple"                      
> (set-box! b '(banana boat))
> b                          
'#&(banana boat)             

+[missing] in [missing] provides more on boxes and box procedures.

12. Void and Undefined

Some procedures or expression forms have no need for a result value. For example, the display procedure is called only for the side-effect of writing output. In such cases the result value is normally a special constant that prints as #<void>. When the result of an expression is simply #<void>, the REPL does not print anything.

The void procedure takes any number of arguments and returns #<void>. (That is, the identifier void is bound to a procedure that returns #<void>, instead of being bound directly to #<void>.)

Examples:

> (void)       
> (void 1 2 3) 
> (list (void))
'(#<void>)     

The undefined constant, which prints as #<undefined>, is sometimes used as the result of a reference whose value is not yet available. In previous versions of Racket before version 6.1, referencing a local binding too early produced #<undefined>; too-early references now raise an exception, instead.

The undefined result can still be produced in some cases by the shared form.

(define (fails)                  
  (define x x)                   
  x)                             
> (fails)                        
x: undefined;                    
 cannot use before initialization