Glossary of Racket concepts
This glossary is still very much work in progress. Many entries are missing.
1 Introduction
The Racket documentation describes a lot, often very abstract concepts. For someone starting with the language, it’s often not clear which concepts are widely used and which aren’t. It’s quite easy to lose one’s way by getting distracted by relatively obscure concepts.
basic: These are basic concepts you should know to write Racket libraries and programs. If you’re starting to learn Racket, focus on these concepts.
Note that “basic” here doesn’t nessarily mean “trivial.” Don’t be discouraged if you don’t understand these glossary entries immediately. Experiment with the code examples or revisit the respective glossary entry later when you have more Racket experience.
intermediate: You can write most Racket software without these features, but you may need them depending on your problem. One example would be threads to execute different tasks concurrently.
advanced: Likely you won’t need these features, but they may improve your software. Look into these if you’re comfortable with the entries in the “basic” and “intermediate” categories.
Not all Racket users will agree on this categorization and the assigned levels for individual terms, but the categorization should give you a rough idea which concepts are more foundational than others.
This glossary isn’t a book for learning Racket, nor is it a reference. Some information may be simplified, for example some special cases may not be mentioned. If you want all the details, check out the Racket Reference.
2 Entries
Arity
Level: basic
The arity describes how many arguments a function can accept. Everything from zero to infinitely many arguments is possible. Note that functions can have optional arguments, so even for a specific function, the arity may not be a single number.
Arity refers only to positional arguments, not keyword arguments.
Procedure in this glossary
Keywords and Arity in the Racket Reference
Assignment
Level: basic
However, in Racket and other functional languages, assignment is used much less than in imperative languages. The “normal” approach in functional languages is to transform immutable values to other immutable values.
To change a value via assignment, you need a name (binding) and a storage location for it. Usually, the binding and location are created with define, but they can also be created by one of the let forms.
Assignment: set! in the Racket Guide
Assignment: set! and set!-values in the Racket Reference
Binding
Level: basic
Note that the bound value is the result of the expression, not the expression itself.
Binding in the Racket Guide
Identifiers, Binding, and Scopes in the Racket Reference
Boolean
Level: basic
#f false
#t true
If a value is interpreted as a condition (as in if or cond forms), only the constant #f is interpreted as false, all other values are interpreted as true.
> (for ([value '(#t 1 0 "false" '() map (void) #f)]) (displayln (if value "true" "false")))
true
true
true
true
true
true
true
false
See also: Booleans in the Racket Reference
Box
Level: intermediate
A box is a container to essentially turn an immutable value into a mutable value. Passing a box as a function argument is similar to passing a value by reference in some other languages.
> (define (func value-box) (define old-value (unbox value-box)) (set-box! value-box (add1 old-value))) > (define a-box (box 7)) > (func a-box) > (displayln (unbox a-box)) 8
As you can see, using boxes is kind of awkward compared to passing arguments by reference in other languages. However, in practice this isn’t a problem since it’s unidiomatic in Racket to use mutable values. Instead you usually transform immutable values to other immutable values.
See also: Boxes in the Racket Reference
Byte string
Level: basic
See String, character, byte string
Call
Level: basic
See Procedure
Channel
Level: intermediate
Chaperone
Level: intermediate
Character
Level: basic
See String, character, byte string
Class
Level: intermediate
Closure
Level: basic
A closure combines a function with environment data from a scope outside the function.
> (define (make-incrementer increment) (lambda (value) (+ value increment))) > (define add3 (make-incrementer 3)) > (add3 5) 8
The return value of make-incrementer is the closure. The lambda expression doesn’t define the increment; the value is taken from the scope outside the lambda expression.
Let over lambda in this glossary
Closure Wikipedia entry
Collection
Level: basic
Combinator
Level: intermediate
Comprehension
Level: basic
Cons cell
Level: basic
See Pair
Continuation
Level: advanced
Contract
Level: intermediate
Core form
Level: advanced
Currying
Level: basic
See Partial application and currying
Custodian
Level: advanced
Debugging
Level: basic
Definition
Level: basic
Display
Level: basic
DrRacket
Level: basic
DSL (domain-specific language)
Level: advanced
Environment
Level: intermediate
Equality
Level: basic
Unless you need to distinguish between different number types, use = instead of the three functions described above.
The name makes it clear what’s compared, without looking at surrounding code.
Functions of this form provided by Racket check that the arguments have the correct type, e.g. string for string=?.
There’s no == function in Racket, but you could define a function with this name. (But probably you shouldn’t.)
Other languages
The eq? function behaves like the is operator in Python.
Exact number
Level: basic
Executor
Level: advanced
Exception
Level: intermediate
Expression (always rvalue? may result in one or more values)
Level: basic
Field
Level: basic
See Struct
Fixnum
Level: basic
Flat contract
Level: advanced
Flonum
Level: basic
Fold
Level: basic
Form
Level: basic
Formatting
Level: basic
Level: intermediate
(‘format‘, ‘~a‘ etc.
Function
Level: basic
See Procedure
Functional programming (FP)
Level: basic
Functional update
Level: basic
Compared to an “imperative update,” as used in many programming languages, a “functional update” doesn’t modifiy a value in place, but instead returns a modified copy.
; Create a hash table for imperative updates. > (define imperative-hash (make-hash '((1 . a) (2 . b)))) > imperative-hash '#hash((1 . a) (2 . b))
; Modify the hash by storing another pair in it. ; The exclamation point at the end of `hash-set!` means ; that the hash is modified in-place. > (hash-set! imperative-hash 3 'c) > imperative-hash '#hash((1 . a) (2 . b) (3 . c))
; Create a hash table for functional updates. > (define functional-hash (make-immutable-hash '((1 . a) (2 . b)))) > functional-hash '#hash((1 . a) (2 . b))
; Return a modified copy of the hash. > (define new-hash (hash-set functional-hash 3 'c)) ; The original hash is unchanged. > functional-hash '#hash((1 . a) (2 . b))
; The change is only visible in the new value. > new-hash '#hash((1 . a) (2 . b) (3 . c))
; Besides, immutable hashes don't allow imperative changes ; (as you probably expected). > (hash-set! functional-hash 4 'd) hash-set!: contract violation
expected: (and/c hash? (not/c immutable?))
given: '#hash((1 . a) (2 . b))
argument position: 1st
other arguments...:
4
'd
The concept of functional updates doesn’t only apply to hashes, but is very common in Functional Programming in general.
Binding, Functional programming (FP), Hash, Naming conventions in this glossary
Future
Level: advanced
Generator
Level: advanced
Generic API
Level: advanced
GUI programming
Level: intermediate
Hash
Level: basic
> (define my-hash (hash #(1 2 3) '(a b c) '(1 2) #t #f map)) > (hash-ref my-hash #(1 2 3)) '(a b c)
> (hash-ref my-hash '(1 2)) #t
> (hash-ref my-hash #f) #<procedure:map>
Combination |
| Construction (1, 2) |
| Set or update value (3) |
| Get value |
equal?/immutable |
| (hash key1 value1 key2 value2 ...)
|
| (hash-set hash key value) |
| (hash-ref hash key) |
eq?/immutable |
| (hasheq key1 value1 key2 value2 ...)
|
| (hash-set hash key value) |
| (hash-ref hash key) |
equal?/mutable |
| (make-hash pair1 pair2 ...) |
| (hash-set! hash key value) |
| (hash-ref hash key) |
eq?/mutable |
| (make-hasheq pair1 pair2 ...) |
| (hash-set! hash key value) |
| (hash-ref hash key) |
(1) You can create empty hashes by calling the constructor without arguments. For example, (hash) creates an empty immutable hash with equal? key comparison.
(2) A pair here is a regular Scheme/Racket pair, for example (cons 1 'a). Pairs that contain only literals can also be written as '(1 . a).
(3) Setting or updating a value in an immutable hash may sound contradictory. The solution is that hash-set causes a so-called functional update. That is, it returns a new hash with the modification applied and leaves the hash argument unchanged. This is the same principle that cons or struct-copy use.
If a hash entry has a mutable key (for example a vector) don’t change the key in-place.
Don’t change a hash while iterating over it.
Collection, Equality, Functional update, List, Pair, Struct, Vector in this glossary
Hash Tables in the Racket Guide
Hash Tables in the Racket Reference
Higher-order function
Level: basic
Hygiene
Level: intermediate
Identifier (differences to identifiers in other languages)
Level: basic
Identity (also refer to ‘eq?‘)
Level: basic
Impersonator
Level: advanced
Inexact number → Exact number
Level: basic
Inspector
Level: advanced
Interface (API)
Level: basic
Interface (OOP)
Level: intermediate
Keyword arguments (positional and keyword args are separate)
Level: basic
Lambda
Level: basic
As shown in the Procedure entry, a procedure can be defined with define. However, you can also define functions directly as values without giving them a name. This is the same function as in the Procedure glossary entry:
> (lambda ([name "world"]) (string-append "Hello " name "!")) #<procedure:eval:41:0>
> ((lambda ([name "world"]) (string-append "Hello " name "!")) "Alice") "Hello Alice!"
The second example above defines and directly calls the function.
The above examples are a bit artifical. Normally, you use a function defined with lambda as a function argument for a Higher-order function or in a Let expression.
Definition, Higher-order function, Let in this glossary
Functions: lambda in the Racket Guide
Procedure Expressions: lambda and case-lambda in the Racket Reference
Lang (as in ‘#lang‘)
Level: advanced
Language-oriented programming
Level: advanced
Let
Level: basic
Let over lambda
Level: intermediate
Here, let creates the outer environent whereas lambda defines the function using that environment.
See also: Procedure, Lambda, Closure in this glossary
List
Level: basic
Lists are the most widely used data structure in many functional programming languages, including Scheme and Racket.
Scheme and Racket lists are implemented as singly-linked lists (with the exception of the empty list, which is an atomic value). Singly-linked lists consist of pairs where the first value of a pair is a list item and the second value of the pair points to the next pair. The end of the list is denoted by an empty list as the second value of the last pair.
For example, the list '(1 2 3 4) can be drawn as
This data structure looks much more complicated than an array, where items are stored in adjacent memory locations. A singly-linked list also has the disadvantage that accessing list items by index requires traversing the list until the pair with the given index is found.
or, in one picture,
So each of the lists looks as you would expect, but it’s not necessary to make any copies of the list data. Instead the lists share some data, without this being visible to code that uses these lists. (An exception is if list items are changeable values, e.g. vectors, and are actually changed in-place. In that case, all lists that share this changed data “see” the change. But usually you should avoid mutating data, partly for this reason.)
Changing lists with cons maximizes the data that can be shared between lists. The situation is different if you change data “further down” the list. In this case, it may be necessary to copy a part of the list data.
Other languages
Note that Scheme/Racket lists are different from “lists” in many other programming languages. Typically those lists store data in adjacent memory locations and have a fast append operation. Racket lists, on the other hand, are singly-linked lists and have a fast prepend operation (cons), but appending items is rather slow because it has to iterate through the whole list and make a copy. The closest equivalent in Racket to the above-mentioned lists in some languages are called growable vectors (see gvector). However, Racket lists are the idiomatic approach for most list processing, so use them if you can.
Collection, Functional update, Pair in this glossary
Pairs and Lists in the Racket Guide
Pairs and Lists in the Racket Reference
Location
Level: basic
A location is an implicitly created memory location. For example, this happens in define or let forms. A consequence of creating a location is that it can be modified with set! or other mutating functions.
> (define (change-argument arg) (displayln arg) (set! arg 5) (displayln arg)) > (change-argument 3)
3
5
> (let ([v (vector 1 2 3)]) (displayln v) (vector-set! v 2 5) (displayln v))
#(1 2 3)
#(1 2 5)
However, usually you should avoid mutation in functional programming.
Macro
Level: intermediate
Level: advanced
Match
Level: intermediate
Match transformer
Level: advanced
Method
Level: intermediate
Module
Level: basic
Named let
Level: intermediate
Namespace
Level: intermediate
Naming conventions
Level: basic
As usual for programming languages, Racket code uses some conventions. As with all conventions, there’s no law enforcing them, but you should follow them if you want your code style to look familiar to other Racket programmers. :-)
Parts of identifiers are separated by hypens (kebap case, e.g. vector-length). Snake case (vector_length) or camel case (vectorLength) are not used. Sometimes module-level constants are in all uppercase, for example (define GRID-ROW-COUNT 10). Other names are all lowercase.
Abbreviations are rare; almost everything is “spelled out.” This can result in rather long names like make-input-port/read-to-peek or call-with-default-reading-parameterization. Most names turn out reasonably short, though.
If a name describes a type and an operation on it, the type usually goes first, as in vector-ref or string-copy. The accessor functions generated by struct also follow this pattern.
Pattern |
| Meaning |
| Examples |
name? |
| Predicate (1) |
| |
name=? |
| Comparison predicate (1) |
| |
name! |
| Mutation |
| |
name* |
| Repetition |
| |
name* |
| Nesting |
| |
name* |
| Other variant |
| |
name% |
| Class name |
| |
part/part |
| “for“ or “with“ |
| |
type->other-type |
| Conversion |
| |
make-type |
| Create new value of type |
|
(1) Since the question mark already identifies a predicate, using prefixes like “is-”, “has-” etc. is redundant.
Functional update, Predicate, Struct in this glossary
Racket Style Guide for other Racket coding conventions
Number
Level: basic
Number types
integer
rational
real
complex
Different from many other programming languages, Scheme/Racket number types don’t directly correspond to how they might be stored on the machine level. Instead, Scheme/Racket number types are closer to the mathematical meanings.
; Simplified and rendered as 2. > 6/3 2
; Can't be simplified and remains a fraction. > 6/7 6/7
; Any integer number is also a rational number, a real number ; and a complex number. > (map rational? '(0 1 -2 2.0 6/3)) '(#t #t #t #t #t)
> (map real? '(0 1 -2 2.0 6/3)) '(#t #t #t #t #t)
> (map complex? '(0 1 -2 2.0 6/3)) '(#t #t #t #t #t)
Exactness
Tips
Functional update, Predicate, Struct in this glossary
Racket Style Guide for other Racket coding conventions
Numeric tower
Level: basic
Opaque
Level: intermediate
See Struct
Package
Level: intermediate
Pair
Level: basic
Pairs, also called cons cells, are the building blocks of Scheme/Racket lists, but are also often used for combining any two values.
> (cons 1 "one") '(1 . "one")
List in this glossary
Pairs and Lists in the Racket Guide
Pairs and Lists in the Racket Reference
Parameter
Level: basic
Partial application and currying
Level: basic
Partial application takes a function with some number of arguments and creates a new function that calls the original function while hard-coding some of the arguments.
The following example defines a function draw-line and a curried version draw-line-from-origin, which hard-codes the from-x and from-y arguments:
> (define (draw-line from-x from-y to-x to-y) ; Keep it simple; just print a string instead of drawing a line. (displayln (format "Drawing a line from (~a, ~a) to (~a, ~a)" from-x from-y to-x to-y))) > (draw-line 1 2 3 4) Drawing a line from (1, 2) to (3, 4)
; Hard-code the first two arguments of `draw-line`.
> (define (draw-line-from-origin to-x to-y) (draw-line 0 0 to-x to-y)) > (draw-line-from-origin 2 3) Drawing a line from (0, 0) to (2, 3)
Currying is similar, but it hard-codes only one argument and, as long as the arguments aren’t complete, returns a function that also takes only one argument.
> (curry draw-line 1) #<procedure:curried:draw-line>
> ((curry draw-line 1) 2) #<procedure:curried:draw-line>
> (((curry draw-line 1) 2) 3) #<procedure:curried:draw-line>
> ((((curry draw-line 1) 2) 3) 4) Drawing a line from (1, 2) to (3, 4)
> (curry draw-line 1) #<procedure:curried:draw-line>
> ((curry draw-line 1) 2) #<procedure:curried:draw-line>
> (((curry draw-line 1) 2) 3 4) Drawing a line from (1, 2) to (3, 4)
Note that the last call passes two arguments, 3 and 4.
There’s also a function curryr, which hard-codes arguments from the right instead of the left of the argument list.
Other languages
Unlike Haskell, Scheme/Racket doesn’t have implicit currying, so the following code raises an exception:
> (define draw-line-from-origin (draw-line 0 0)) draw-line: arity mismatch;
the expected number of arguments does not match the given
number
expected: 4
given: 2
Pattern (in regular expressions)
Level: basic
Pattern (in macro definitions)
Level: intermediate
Phase
Level: advanced
Place
Level: advanced
Polymorphism (rarely used, compare with other languages; see also generic code)
Level: intermediate
Port
Level: basic
Predicate
Level: basic
A predicate is a procedure that takes one argument and returns a boolean.
Checking for a type: procedure?, string?, symbol?, ...
Checking properties: even?, immutable?, char-lower-case?, ...
Others: directory-exists?, file-exists?, ...
Lambda, Partial application and currying, Procedure in this glossary
Level: basic
See Display
Procedure
Level: basic
A procedure, also called a function, is a value that can be called at program runtime. If a procedure is used after an opening parenthesis, it introduces a function call. For example, add1 is a simple function that adds 1 to its argument:
> (add1 2) 3
If a function should be called without arguments, it’s written (func). Since the parentheses cause the function call, you can’t just add brackets around expressions. For example,
> ((add1 2)) application: not a procedure;
expected a procedure that can be applied to arguments
given: 3
calculates 3 through the function call (add1 2) and tries to call the result 3 as a function, (3), which gives an error saying that 3 isn’t callable.
On the other hand, when using a function in another position, it’s just a “passive” value:
> add1 #<procedure:add1>
> (procedure? add1) #t
> (list add1 add1) '(#<procedure:add1> #<procedure:add1>)
As using too many brackets, using too few can lead to problems, although they tend to be less obvious:
You might have expected 3 as the result of calling foo. However, since the parentheses around add1 2 were missing and the result of a function is the value of the last expression, the function returned 2.
Depending on how a function is defined, it can take zero arguments to an almost unlimited number of arguments (usually done with a special syntax in the function definition).
The following function takes an optional argument and returns a string to greet someone:
> (define (greeting [name "world"]) (string-append "Hello " name "!")) > (greeting) "Hello world!"
> (greeting "Bob") "Hello Bob!"
Lambda in this glossary
Simple Definitions and Expressions in the Racket Guide
Definitions: define, define-syntax, ... in the Racket Reference
Profiling
Level: intermediate
Prompt
Level: advanced
Provide
Level: intermediate
Quasiquote
Level: intermediate
Quote
Level: basic
RnRS (as in R5RS, R6RS etc.)
Level: intermediate
Raco
Level: basic
Reader (for parsing code)
Level: advanced
Record
Level: basic
See Struct
Require
Level: basic
Rule (in macros; probably other uses, which ones?)
Level: intermediate
Safe operation
Level: intermediate
See Unsafe operation
Scheme
Level: basic
Scribble
Level: intermediate
Sequence
Level: intermediate
Set
Level: intermediate
Shadowing
Level: basic
Splicing
Level: basic
SRFI
Level: intermediate
Standard library
Level: basic
Stream
Level: basic
String, character, byte string
Level: basic
The string, byte string and character data types are used for text processing.
; String content enclosed in quotes > "a string" "a string"
> (string? "a string") #t
; A quote inside a string literal can be escaped with a backslash. > "a string \"with\" quotes" "a string \"with\" quotes"
> (string-length "\"foo\"") 5
; Use `display` or `displayln` to output a string for human readers. ; `displayln` adds a newline. > (displayln "a string \"with\" quotes") a string "with" quotes
; Concatenate strings with `string-append`. > (string-append "Hello " "world" "!") "Hello world!"
; Strings can contain non-ASCII characters. > "Michael Müller" "Michael Müller"
> (string-length "Michael Müller") 14
; You can get individual characters with `string-ref`. > (string-ref "Müller" 1) #\ü
> (char? #\ü) #t
; Convert a string to a character list and back. > (string->list "Müller") '(#\M #\ü #\l #\l #\e #\r)
> (list->string '(#\M #\ü #\l #\l #\e #\r)) "Müller"
; Not the only encoding function in the standard library > (define encoded-string (string->bytes/utf-8 "Müller")) ; ü has been encoded to two bytes. > encoded-string #"M\303\274ller"
> (bytes? encoded-string) #t
; Not the only decoding function in the standard library > (bytes->string/utf-8 encoded-string) "Müller"
Fortunately, as long as the content is in UTF-8 encoding, you don’t need to encode or decode it yourself. For example, file->string decodes the file contents implicitly.
> (bytes->list encoded-string) '(77 195 188 108 108 101 114)
The following diagram shows the relationships between the types:
Both strings and byte strings come in mutable and immutable versions. Literals, e.g. "foo" or #"foo", are immutable.
The term “character” is ambiguous in the unicode context. It can mean a code point (as in Racket), but also a symbol on the screen that’s perceived as self-contained. The second meaning is sometimes called a “grapheme“ or “grapheme cluster.”
- The distinction between the meanings of “character” are important because not all grapheme clusters can be expressed in a single code point. For example, the German flag 🇩🇪 consists of two code points:
> (string->list "🇩🇪") '(#\🇩 #\🇪)
In some cases, the same grapheme cluster can be expressed in different code point combinations. For example, the string "ü" from above can be expressed in a single code point, but alternatively in two code points, where the first is for the letter "u" and the second for the diacritic (the dots above the u). So two strings that look the same on the screen may not be the same according to Racket’s string=? function, which works on code point sequences.
The normalization functions can convert strings so that they have the “combined” or the “separate” code points and can be meaningfully compared with string=?.
Formatting, Port in this glossary
Strings (Unicode), Bytes and Byte Strings in the Racket Guide
Strings, Byte Strings, Characters, Encodings and Locales in the Racket Reference
Struct
Level: basic
Although Racket has an OOP system, the primary way to group information for a type is using a struct and functions related to it.
> (struct person (name age))
Here, person is the name of the struct and name and age are the fields of the struct.
Creating a struct like above creates several bindings. One is for the name of the struct, which can be used to create instances of the struct:
> (define bilbo (person "Bilbo Baggins" 111)) > bilbo #<person>
Moreover, each field results in a binding named struct-name-field-name to access the value of each field in a given struct instance:
> (person-name bilbo) "Bilbo Baggins"
> (person-age bilbo) 111
It’s also possible to declare a struct as mutable by adding a #:mutable keyword. This creates additional accessor functions to set values in a struct instance. However, you usually should avoid mutation in Racket. Instead, use struct-copy to create a new struct instance based on another instance:
> (define younger-bilbo (struct-copy person bilbo [age 100])) > (person-name younger-bilbo) "Bilbo Baggins"
> (person-age younger-bilbo) 100
See also Functional update. You can use more than one field name/value pair.
By default, structs are created as opaque. This means that printing a struct instance doesn’t show the values. More important is the gotcha that comparing opaque struct instances with equal? compares by identity (like eq?), not by field values!
> (define bilbo2 (person "Bilbo Baggins" 111)) > (equal? (person-name bilbo) (person-name bilbo2)) #t
> (equal? (person-age bilbo) (person-age bilbo2)) #t
> (equal? bilbo bilbo2) #f
Adding the #:transparent keyword to the struct definition avoids this problem:
> (struct person (name age) #:transparent) > (define frodo (person "Frodo Baggins" 33)) > frodo (person "Frodo Baggins" 33)
> (define frodo2 (person "Frodo Baggins" 33)) > (equal? (person-name frodo) (person-name frodo2)) #t
> (equal? (person-age frodo) (person-age frodo2)) #t
> (equal? frodo frodo2) #t
Printing frodo shows the struct values, not just #<person>.
Comparing two struct instances of the same transparent struct type with the same values with equal? gives #t.
The latter is not only more intuitive, but it’s also very useful when comparing calculated and expected struct instances in automated tests.
That said, values of different struct types compare as #f, even if the field names are the same.
Although Racket uses opaque structs for stronger encapsulation and backward-compatibility, many Racket users nowadays think that defining structs as transparent usually gives the better tradeoff.
Other languages
Note that field names are only known at compile time, not at runtime. This means that a function like Python’s getattr doesn’t exist in Racket.
Binding, Functional update in this glossary
Programmer-Defined Datatypes, Classes and Objects in the Racket Guide
Defining Structure Types: struct, Classes and Objects in the Racket Reference
Symbol
Level: basic
> "a-string" "a-string"
> 'a-symbol 'a-symbol
Symbols are idiomatically used for enumeration values. See the open-output-file function for an example, which uses symbols for the mode and exists keyword arguments.
By default, symbols are interned, while there’s no such guarantee for strings. Interning has the consequence that two “same” symbols compare equal with eq?, not just with equal?. Therefore, hashes that have symbols as keys can use the eq? variants, which speeds up the hash operations.
Because of the different uses of strings and symbols, the standard library has no APIs to search in symbols or concatenate them. If you need such functionality, you can convert between symbols and strings with symbol->string and string->symbol.
Syntactic form
Level: basic
See Form
Syntax (different meanings)
Level: intermediate
Syntax transformer
Level: intermediate
See Macro
Tail call
Level: intermediate
Tail position
Level: intermediate
Thread
Level: intermediate
Thunk
Level: basic
Transparent
Level: basic
See Struct
Trust level
Level: advanced
Trusted code
Level: advanced
See Untrusted code
Typed Racket
Level: advanced
Undefined (why do we need this if we have ‘void‘?)
Level: advanced
Unit
Level: advanced
Unsafe operation
Level: intermediate
Untrusted code
Level: advanced
Value (sometimes "object", but may be confused with OOP concept)
Level: basic
Values (multiple values, as in ‘define-values‘ etc.)
Level: basic
Vector
Level: basic
Racket vectors are continuous arrays with indices starting at 0. An advantage of vectors over lists is that accessing a vector item at a random index takes constant time, i.e. is independent of the vector size and the index.
; Simple vector with some numbers. > #(1 2 3) '#(1 2 3)
; Empty vector > #() '#()
; Items are quoted. This vector does _not_ contain the `map` function. > (define vec1 #(map)) > (vector-ref vec1 0) 'map
; Use `vector` to avoid quoting. > (define vec2 (vector map)) > (vector-ref vec2 0) #<procedure:map>
> (define vec1 #(1 2 3)) > (vector-set! vec1 1 5) vector-set!: contract violation
expected: (and/c vector? (not/c immutable?))
given: '#(1 2 3)
> (define vec2 (vector-immutable 1 2 3)) > (vector-set! vec2 1 5) vector-set!: contract violation
expected: (and/c vector? (not/c immutable?))
given: '#(1 2 3)
> (define vec3 (vector 1 2 3)) > (vector-set! vec3 1 5) > vec3 '#(1 5 3)
There are several vector functions (e.g. vector-map or vector-filter) that correspond to similar list functions. If the existing vector functions aren’t enough, it may make sense to convert a vector to a list with vector->list, process the list with list functions and finally convert the list back to a vector with list->vector.
Collection, List in this glossary
Vectors in the Racket Guide
Vectors in the Racket Reference
Void
Level: basic
The constant #<void> is used as a return value if there’s no other sensible value. This applies to functions that exist only for their side effects or if no branch in a cond or case form matches.
Experimenting with #<void> can be confusing because the Racket REPL (interactive interpreter) doesn’t show it, but you can check the result for being #<void> with the void? predicate.
Another curiosity is that you can’t enter the #<void> value in source code or the REPL. However, you can create the value with the void function.
Other languages
Python has a value None, whose semantics is similar to #<void>. However, while the use of None in Python is idiomatic to denote an unset optional argument, Scheme and Racket code typically uses #f for the same purpose.Example:
> (define (hello [who #f]) (string-append "Hello, " (if who who "world") "!")) > (hello) "Hello, world!"
> (hello "Mike") "Hello, Mike!"
Since #f is the only value that’s treated as false in conditions, this usage normally makes sense.That said, it’s fine to use (void) and check the argument with void? if #f could be an actual value for the argument.
Will
Level: advanced
Write
Level: basic
See Display
Writer
Level: advanced