Glossary of Racket concepts
1 Introduction
2 Entries
Arity
Assignment
Binding
Boolean
Box
Byte string
Call
Channel
Chaperone
Character
Class
Closure
Collection
Combinator
Comprehension
Cons cell
Continuation
Contract
Core form
Currying
Custodian
Debugging
Definition
Display
Dr  Racket
DSL (domain-specific language)
Environment
Equality
Exact number
Executor
Exception
Expression
Field
Fixnum
Flat contract
Flonum
Fold
Form
Formatting and output
Function
Functional programming (FP)
Functional update
Future
Generator
Generic API
GUI programming
Hash
Higher-order function
Hygiene
Identifier
Identity
Impersonator
Inexact number
Inspector
Interface (API)
Interface (OOP)
Keyword
Lambda
Lang (as in ‘#lang‘)
Language-oriented programming
Let
Let over lambda
List
Location
Macro
Match
Match transformer
Method
Module
Named let
Namespace
Naming conventions
Number
Numeric tower
Opaque
Package
Pair
Parameter
Partial application and currying
Pattern (in regular expressions)
Pattern (in macro definitions)
Phase
Place
Polymorphism
Port
Predicate
Print
Procedure
Profiling
Prompt
Provide
Quasiquote and unquote
Quote
Rn  RS (as in R5RS, R6RS etc.)
Raco
Reader (for parsing code)
Record
Require
Rule (in macros; probably other uses, which ones?)
Safe operation
Scheme
Scope
Scribble
Sequence, stream, generator
Set
Shadowing
Splicing
SRFI
Standard library
Stream
String, character, byte string
Struct
Symbol
Syntactic form
Syntax (different meanings)
Syntax transformer
Tail call
Tail position
Testing
Thread
Thunk
Transparent
Trust level
Trusted code
Typed Racket
Undefined
Unit
Unsafe operation
Untrusted code
Value
Values
Vector
Void
Will
Write
Writer
8.12

Glossary of Racket concepts🔗ℹ

Stefan Schwarzer

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.

This led to a discussion on the Racket forum and during this discussion to the plan to start this glossary. The intention is to list many concepts, even the obscure ones, together with their importance, given by these levels:
  • 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.

See also:

Assignment🔗ℹ

Level: basic

Assigning means the same as in most programming languages: changing the value of a variable. To change the value of a variable, use set!:
> (define my-variable 2)
> (displayln my-variable)

2

> (set! my-variable 5)
> (displayln my-variable)

5

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.

See also:

Binding🔗ℹ

Level: basic
A binding makes a value accessible via a name. Typically, bindings are created with the define form:
> (define x (+ 2 3))
binds the name x to the value 5.

Note that the bound value is the result of the expression, not the expression itself.

See also:

Boolean🔗ℹ

Level: basic
Booleans represent truth values. In some other languages this type is called bool or boolean. Racket has two boolean literals:
  • #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.

Example:
> (for ([value (list #t 1 0 "false" '() map (void) #f)])
    (displayln (if value "true" "false")))

true

true

true

true

true

true

true

false

See also:

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.

Example:
> (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

In Racket, 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

Call🔗ℹ

Level: basic

Channel🔗ℹ

Level: intermediate

Chaperone🔗ℹ

Level: intermediate

Character🔗ℹ

Level: basic

Class🔗ℹ

Level: intermediate

Closure🔗ℹ

Level: basic
A closure combines a function with environment data from a scope outside the function.

Example:
> (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.

See also:

Collection🔗ℹ

Level: basic

Combinator🔗ℹ

Level: intermediate

Comprehension🔗ℹ

Level: basic
In Racket, a comprehension is a form that maps one or more sequences to another sequence as described by an expression. Typically, this definition means the for forms that create sequences, like lists or vectors.

For example, here’s a simple list comprehension:
> (for/list ([i (in-range 5)])
    (* 2 i))

'(0 2 4 6 8)

The comprehension forms can be classified by two criteria:
  • Type of the generated sequence. For example, for/list creates a list and for/vector creates a vector.

  • Parallel or nested iteration. This is only relevant if the form uses more than one input sequence. The for forms iterate in parallel; the for* forms iterate in a nested fashion.

Here are two more examples to illustrate these criteria:
; Parallel iteration creating a list.
> (for/list ([index (in-range 1 4)]
             [word '("one" "two" "three")])
    (format "~a/~a" index word))

'("1/one" "2/two" "3/three")

; Nested iteration creating a vector. Note the `*` in `for*/vector`.
> (for*/vector ([color '("green" "red")]
                [fruit '("apple" "berry")])
    (format "~a ~a" color fruit))

'#("green apple" "green berry" "red apple" "red berry")

A few more details:
  • There are a lot of sequences that can be iterated over, for example, strings (iterating over characters) or ports (iterating over characters, bytes or lines).

  • The “loop body” doesn’t have to be single expression. See the examples in the Racket Guide.

  • If sequences are iterated over in parallel, the shortest input sequence determines the elements used for the comprehension.

  • The for forms support several keyword arguments. For example, #:when makes it possible to include only certain elements in the result sequence.

  • Forms like for, for/fold or for/and may not be considered comprehensions because they don’t map input elements to output elements but only create a single element. But of course these forms can be useful, too.

See also:

Cons cell🔗ℹ

Level: basic
See Pair

Continuation🔗ℹ

Level: advanced

Contract🔗ℹ

Level: intermediate

Core form🔗ℹ

Level: advanced

Currying🔗ℹ

Level: basic

Custodian🔗ℹ

Level: advanced

Debugging🔗ℹ

Level: basic

Definition🔗ℹ

Level: basic
A definition binds an expression result to a new name. In other words, a definition creates a binding.

By far the two most used ways to define something use define, but in different ways.

First,
(define name expression)
evaluates the expression and binds it to name:
> (define two 2)
> two

2

> (define six (* 3 two))
> six

6

Second,
(define (name arguments) body)
creates a procedure with the name name, arguments arguments and the code to execute, body.

Example:
> (define (hello who)
    (displayln (string-append "Hello, " who "!")))
> (hello "Mike")

Hello, Mike!

Apart from those two definition forms, there are many more. Here are a few examples:
  • define-values is similar to the first define form above, but it can create several bindings at the same time in case a procedure returns more than one value.

  • define-syntax defines macros (forms). (But there are many more ways to define macros.)

  • define-check defines custom checks for automated tests.

  • define-runtime-path defines runtime paths.

  • define/public defines a public method for a class.

Although many names of definition forms start with define- or define/, this isn’t required. In a loose sense you could consider anything that creates a new binding as a definition. For example, struct creates not only a constructor, but also accessor functions:
> (struct point (x y))
> point-x

#<procedure:point-x>

> point-y

#<procedure:point-y>

See also:

Display🔗ℹ

Level: basic

DrRacket🔗ℹ

Level: basic

DSL (domain-specific language)🔗ℹ

Level: advanced

Environment🔗ℹ

Level: intermediate

Equality🔗ℹ

Level: basic
Scheme and Racket have three generic functions to determine if two values are equal:
  • equal? checks for value equality. Most of the time, this is the function you want. equal? can also compare recursively, as long as the participating types support equal? comparisons.

    Examples:
    > (equal? (+ 2 3) 5)

    #t

    > (equal? "foo" "foo")

    #t

    > (equal? "foo" "fox")

    #f

    > (equal? '(1 2 3) '(1 2 3))

    #t

    > (equal? '(1 2 ("foo" 3)) '(1 2 ("foo" 3)))

    #t

    > (equal? '(1 2 ("foo" 3)) '(1 2 ("bar" 3)))

    #f

  • eq? checks object identity, i.e. eq? only returns #t if the two compared values are one and the same object. This is especically important for mutable objects. For immutable values object identity is less relevant.

    Examples:
    ; There's only one `#t` constant.
    > (eq? #t #t)

    #t

    ; Compare with the same list object.
    > (define a-list '(1 2))
    > (eq? a-list a-list)

    #t

    ; Two different list objects
    > (eq? '(1 2) '(1 2))

    #f

  • eqv? behaves mostly like eq?, with the exception of types that have a different implementation. This mainly applies to numbers, but then you probably want to use = anyway.

Unless you need to distinguish between different number types, use = instead of the three functions described above.

The Racket standard library also has many functions of the form type=?, for example string=?. Often these functions are equivalent to equal? for the same arguments. However, using the type=? functions has two advantages:
  • 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.

See also:

Exact number🔗ℹ

Level: basic
See Number

Executor🔗ℹ

Level: advanced

Exception🔗ℹ

Level: intermediate

Expression🔗ℹ

Level: basic
As in other languages, a Racket expression is code that can be evaluated to a result. The result may be #<void> or undefined, but that’s still a result. Different from other languages, an expression may evaluate to more than one value. See the Values entry for more information on this.

Examples of expressions are:
; Literal values
> 3

3

> "foo"

"foo"

; A name bound to a value
> (define foo 3)
> foo

3

; Functions are just a special case of this.
> +

#<procedure:+>

> map

#<procedure:map>

; Function application
> (+ 2 3)

5

> (even? 6)

#t

; Macro applications that evaluate to a value
> (or #t #f)

#t

> (if (> 5 2) "foo" "bar")

"foo"

; Combinations
> (* (+ 2 3) (- 7 3))

20

> (map even? '(1 2 3))

'(#f #t #f)

A way to test if something is an expression is to feed it to a function that accepts an expression regardless of its type. If you don’t get an exception, the argument is an expression. We don’t care about the return value of the function for the test.

Here we use number? as an example of such a function:
; Actual expressions
> (number? 2)

#t

> (number? "foo")

#f

> (number? map)

#f

> (number? (or #t #f))

#f

; No expressions
> (number? if)

eval:53:0: if: bad syntax

  in: if

> (number? (define foo 3))

eval:54:0: define: not allowed in an expression context

  in: (define foo 3)

However, the opposite isn’t necessarily true. You can get an exception even for an expression:
; The expression itself raises an exception.
> (number? (/ 1 0))

/: division by zero

; The expression returns multiple values.
> (number? (values 3 4))

result arity mismatch;

 expected number of values not received

  expected: 1

  received: 2

Note: Although many expressions don’t have a side effect, some do. Therefore, don’t evaluate expressions if they may have “dangerous” side effects, like deleting a file (unless that’s what you want, of course).

See also:

Field🔗ℹ

Level: basic
See Struct

Fixnum🔗ℹ

Level: intermediate
A fixnum is a “small” integer that can be processed with CPU instructions for integers.

Note that fixnums in various Scheme implementations or in Racket can’t store 32 or 64 bits. Some of the bits are used as flags that distinguish fixnums from other values. Even for the same Racket version, different platforms may have a different number of available fixnum bits.

Usually, you should use regular integers and consider the existence of fixnums an implementation detail. That said, using fixnum-specific operations can help with runtime optimizations. Then again, don’t optimize anything until you have profiled your software and therefore are sure that the specific integer calculation is an actual bottleneck.

Other languages
Especially statically-typed languages often have integer types corresponding to 8, 16, 32 and 64 bits. However, in Racket you can’t expect that all bits of a machine integer (for example with 64 bits) are available for calculations (see above).

See also:

Flat contract🔗ℹ

Level: advanced

Flonum🔗ℹ

Level: intermediate
A flonum is an IEEE 754 floating point value. In Racket, this is a value of the “technical” float type (see the Number entry).

See also:

Fold🔗ℹ

Level: basic
Folding means taking a data structure and combining its elements into a new value.

Racket provides the foldl and foldr functions for this. In Scheme implementations, these functions may be called differently. Both fold variants take a function, an initial value and one or more lists. To keep things simple, let’s discuss the case of foldl with a single list argument first.

The provided function is first called with the first list item and the initial value and must return an accumulated value for these arguments. For each subsequent item from the input list the provided function is called again with the list item and the so-far accumulated value.

Here’s an example for calculating the sum from a list of numbers:
> (foldl + 0 '(1 2 3 4 5))

15

which corresponds to
> (+ 5 (+ 4 (+ 3 (+ 2 (+ 1 0)))))

15

The difference between foldl and foldr is that for foldl the input list is processed from left to right and for foldr from right to left.

This difference doesn’t matter for summing numbers as above, but it does for creating a new list:
> (foldl cons '() '(1 2 3 4 5))

'(5 4 3 2 1)

> (foldr cons '() '(1 2 3 4 5))

'(1 2 3 4 5)

The fold functions are quite general. For example, the functions map and filter can be expressed in terms of foldr:
> (define (map-foldr func lst)
    (foldr
      (lambda (item current-list)
        (cons (func item) current-list))
      '()
      lst))
> (map-foldr add1 '(1 2 3 4 5))

'(2 3 4 5 6)

> (define (filter-foldr pred? lst)
    (foldr
      (lambda (item current-list)
        (if (pred? item)
            (cons item current-list)
            current-list))
      '()
      lst))
> (filter-foldr even? '(1 2 3 4 5))

'(2 4)

If foldl or foldr get multiple list arguments, they’re iterated over in parallel and the provided function receives corresponding items from the lists:
> (foldr
    (lambda (item1 item2 current-list)
      (cons (+ item1 item2) current-list))
    '()
    '(1 2 3 4 5)
    '(1 3 5 7 9))

'(2 5 8 11 14)

Racket also has a for/fold form which often is easier to use. For example, map could be implemented as
> (define (map-for/fold func lst)
    (for/fold ([current-list '()])
              ([item (reverse lst)])
      (cons (func item) current-list)))
> (map-for/fold add1 '(1 2 3 4 5))

'(2 3 4 5 6)

Note the reverse call because the list is iterated over from left to right, as in foldl.

See also:

Form🔗ℹ

Level: basic

Formatting and output🔗ℹ

Level: basic
Basics

You can print a string (or other data) with display:
> (display "Hello world!")

Hello world!

A line break can be added with a following newline call. The function displayln combines display and newline, that is, it prints the string and then a line break.

All of these functions take an additional optional argument, which is the port the string or newline should be sent to. By default, this is standard output.

Formatting

A string argument for display or displayln can be built with any string functions, but often it’s convenient to use the format function. It takes a string template with placeholders and the values that should be inserted for these placeholders. Additionally, a few special placeholders, like ~n for a newline, are supported. The values after the template don’t have to be strings.

Examples:
> (format "Hello world!")

"Hello world!"

> (format "Hello ~a!~n" "world")

"Hello world!\n"

> (format "First line~nSecond line~n")

"First line\nSecond line\n"

> (format "~a plus ~a is ~a" 2.5 3 5.5)

"2.5 plus 3 is 5.5"

; ~x, ~o and ~b can only be used with exact numbers.
> (format "decimal: ~a, hexadecimal: ~x, octal: ~o, binary: ~b" 12 -12 13/10 12/7)

"decimal: 12, hexadecimal: -c, octal: 15/12, binary: 1100/111"

Note that using ~n is different from using the string "\n" in that ~n will result in the character combination "\r\n" on Windows.

There are two placeholders, ~v and ~s, which are similar to ~a, but behave differently for strings and compound data.

The placeholder ~v formats values as if they would be output in an interactive interpreter (REPL).

Examples:
> (format "~v" 2)

"2"

> (format "~v" 'abc)

"'abc"

> (format "~v" "abc")

"\"abc\""

> (format "~v" (list 1 2 3))

"'(1 2 3)"

> (format "~v" map)

"#<procedure:map>"

On the other hand, the placeholder ~s is the counterpart of the read function, which converts a string of Racket code, usually to an atomic value or a list of symbols. The following examples use a helper function roundtrip that uses the ~v placeholder from the previous paragraph to show the data returned by the read function. The function open-input-string is explained in the Port glossary entry.

Examples:
> (define (roundtrip str)
    (define read-data
      (read (open-input-string str)))
    (displayln (format "~v" read-data))
    (format "~s" read-data))
> (roundtrip "2")

2

"2"

> (roundtrip "map")

'map

"map"

> (roundtrip "\"abc\"")

"abc"

"\"abc\""

> (roundtrip "(+ 1 2)")

'(+ 1 2)

"(+ 1 2)"

Note that the argument of roundtrip and the result from format in the helper function are the same.

Apart from using format, there’s another approach to format values, the functions ~a, ~v and ~s. There’s also a function ~r for detailed formatting of numbers. The first three functions can take multiple arguments, but the behavior may be surprising if used with keyword arguments for width and alignment (see below).

Examples:
; Use ~a, ~v and ~s on different types of values.
> (~a 2)

"2"

> (~v 2)

"2"

> (~s 2)

"2"

> (~a "abc")

"abc"

> (~v "abc")

"\"abc\""

> (~s "abc")

"\"abc\""

> (~a '(+ 2 3))

"(+ 2 3)"

> (~v '(+ 2 3))

"'(+ 2 3)"

> (~s '(+ 2 3))

"(+ 2 3)"

> (~a map)

"#<procedure:map>"

> (~v map)

"#<procedure:map>"

> (~s map)

"#<procedure:map>"

; `~a` doesn't insert spaces on its own, so you need to add them.
> (~a 2.5 " plus " 3 " is " 5.5)

"2.5 plus 3 is 5.5"

; Use keywords for alignment.
> (~a 1.23 #:width 10 #:align 'right)

"      1.23"

; But keywords are _not_ applied to _each_ of the arguments.
> (~a 1 2 3 #:width 10 #:align 'right)

"       123"

; Number formatting.
> (~r 12.3456 #:notation 'exponential #:precision 2 #:min-width 10)

"  1.23e+01"

Output

So far, we’ve only used display and displayln to actually output something as we’d do it in a program. Other outputs in the examples were formatted strings in the examples’ REPL.

Here are the functions printf, print and write that format and output data:
; `printf` is like `display` and `format`.
> (display (format "~a and ~v" "foo" "foo"))

foo and "foo"

> (printf "~a and ~v" "foo" "foo")

foo and "foo"

; `print` is like `display` and `format` with ~v formatting.
> (display (format "~v" '(1 2 3)))

'(1 2 3)

> (display (~v '(1 2 3)))

'(1 2 3)

> (print '(1 2 3))

'(1 2 3)

; `write` is like `display` and `format` with ~s formatting.
> (display (format "~s" '(1 2 3)))

(1 2 3)

> (display (~s '(1 2 3)))

(1 2 3)

> (write '(1 2 3))

(1 2 3)

All of display, print, write and their variants with an ln suffix accept an optional port argument, so you can write the data to a file or network socket, for example. There’s also a function fprintf, which is like printf but takes a port as first argument.

Serialization and deserialization

If you want to save a data structure and restore it later, you can use serialize and write to save the data and read and deserialize to restore it.

Pretty-printing

Sometimes you may want to output a nested data structure for debugging. You can use pretty-print for this:
> (define data
    '("This is an example line"
      "Here's another one"
      "And some nested data"
      '(1 2 3)
      "And some more text"))
> (pretty-print data)

'("This is an example line"

  "Here's another one"

  "And some nested data"

  '(1 2 3)

  "And some more text")

However, for “short” data, pretty-print may insert fewer line breaks than you’d like, or none at all:
> (define data
    '("foo"
      '(1 2 3)
      "bar"))
> (pretty-print data)

'("foo" '(1 2 3) "bar")

A workaround is to reduce the line width by setting the pretty-print-columns parameter:
> (define data
    '("foo"
      '(1 2 3)
      "bar"))
> (parameterize ([pretty-print-columns 10])
    (pretty-print data))

'("foo"

  '(1 2 3)

  "bar")

In particular, setting pretty-print-columns to 1 prints all items on individual lines:
> (define data
    '("foo"
      '(1 2 3)
      "bar"))
> (parameterize ([pretty-print-columns 1])
    (pretty-print data))

'("foo"

  '(1

    2

    3)

  "bar")

Summary

The following table summarizes some of the previous information:

Main purposes

 

format/printf placeholder

 

Formatting function

 

Output functions

Human-readable output, formatted string output

 

~a

 

~a

 

display, displayln

REPL, debugging

 

~v

 

~v

 

print, println

Processing Racket code (usually used with read)

 

~s

 

~s

 

write, writeln

Number formatting

 

 

~r

 

As shown above, there are a lot of – often redundant – ways to format and output values. For a minimal and in most cases appropriate toolset, use

Examples:
> (define first-name "Bilbo")
> (define last-name "Baggins")
> (displayln (format "~a ~a" first-name last-name))

Bilbo Baggins

> (displayln (~a first-name " " last-name))

Bilbo Baggins

> (printf "~a ~a~n" first-name last-name)

Bilbo Baggins

If the placeholder handling in format and printf isn’t enough, you can get more control over the formatting with the ~a, ~v, ~s and ~r functions, for example to set a width or alignment.

See also:

Function🔗ℹ

Level: basic

Functional programming (FP)🔗ℹ

Level: basic
The core idea of functional programming is that a program should behave like a mathematical function. That is, a program consists of nested expressions that are evaluated to get a result, instead of changing state as in imperative programming.

For example, this is imperative code to set a variable depending on a condition:
; The actual value of `condition` doesn't matter for the example.
> (define condition #t)
> (define number 0)
> (if condition
      (set! number 1)
      (set! number 2))
> number

1

However, this is very atypical code for a functional programming language. In Scheme or Racket you’d write this code more like this:
> (define number
    (if condition
        1
        2))
> number

1

In the second example, the value of number is only set once.

In imperative languages, loops typically update one or more values during each loop iteration. On the other hand, in functional programming languages, it’s typical to use recursion, as in this factorial function:
> (define (factorial n)
    (if (= n 0)
        1
        (* n (factorial (sub1 n)))))
> (factorial 10)

3628800

Note that this code doesn’t use any variables. The if form calculates an expression and this is also the return value of the function. (Note: You can often avoid explicit recursion by using higher-order functions and comprehensions; see the cross references.)

A desired property of a function is that it’s “pure”, that is, it always returns the same result if it’s called with the same arguments, and the function doesn’t have any side effects (like I/O). That way, it’s easier to reason about and test the code. However, since a program that doesn’t have any effects on the outside world is useless, some side effects are needed. To still make the most of pure functions, try to put as much code as possible into pure functions and use them from the code with side effects.

Another feature of functional programming languages is that functions can be used in expressions (also without calling them). In the following example, the if expression evaluates to a function and this function is used to calculate the final result.
> (define condition #t)
> (define my-function
    (if condition
        (lambda (x) (+ x 2))
        (lambda (x) (- x 3))))
> (my-function 3)

5

See also:

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.

Here’s an example of an imperative update:
; 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))

With an imperative update, every piece of code that has a binding to the hash will “see” any changes to the hash. Depending on your design, this can be good or bad. In any case you have to be careful that all locations where the hash is used are prepared for a change “under their feet.”

On the other hand, here’s a corresponding functional update:
; 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

A functional update has the advantage that you can more easily control which code “sees” which value.

The concept of functional updates doesn’t only apply to hashes, but is very common in Functional Programming in general.

See also:

Future🔗ℹ

Level: advanced

Generator🔗ℹ

Level: intermediate

Generic API🔗ℹ

Level: advanced

GUI programming🔗ℹ

Level: intermediate

Hash🔗ℹ

Level: basic
Hashes, also called hash tables, hash maps or dictionaries, map keys to values. For example, the following hash table maps numbers to symbols:
> (define my-hash
    (hash 1 'a
          2 'b
          3 'c))
; Look up the value for the key 2.
> (hash-ref my-hash 2)

'b

Keys and values can be arbitrary values:
> (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>

However, usually all keys are of the same type and all values are of the same type.

The API for hashes in Racket is more complicated than for the other compound data structures like lists and vectors. Hashes can differ in the following criteria; all of the combinations are possible:
  • Comparison for keys: equal?, eq?, eqv?

  • Mutability: immutable, mutable
    Mutability applies to the hash as a whole, not to the mutability of the keys or the values.

  • Strength: strong, weak, ephemerons
    This influences when hash entries can be garbage-collected.

These are 3×2×3 = 18 combinations, but in practice you can almost always get by with these four combinations:
  • Comparison for keys: equal?, eq?

  • Mutability: immutable, mutable

  • Strength: strong

Here’s an overview of the most important APIs for these four equality/mutability combinations:

Combination

 

Construction (1, 2)

 

Set or update value (3)

 

Get value

equal?/immutable

 

(hash key1 value1 key2 value2 ...)
or
(make-immutable-hash pair1 pair2 ...)

 

(hash-set hash key value)

 

(hash-ref hash key)

eq?/immutable

 

(hasheq key1 value1 key2 value2 ...)
or
(make-immutable-hasheq pair1 pair2 ...)

 

(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.

Warnings:
  • 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.

See also:

Higher-order function🔗ℹ

Level: basic
A higher-order function is a function that takes a function as an argument and/or returns a function. This approach is very common in functional programming.

Here are a few examples of higher-order functions:
  • map takes a function that transforms a list item to another item for the result list.

  • filter takes a predicate function that determines which list items should be included in the returned list.

  • sort takes a comparison function that determines the sort order of the returned list.

  • compose takes one or more functions and returns a function that applies the functions one after another.

See also:

Hygiene🔗ℹ

Level: intermediate

Identifier🔗ℹ

Level: basic
As in other programming languages, an identifier is a name assigned to a value (or a form). Compared to most languages, identifiers can contain a lot more characters. In Racket, all of the following identifier names are valid:
> (define a-name 2)
> a-name

2

> (define predicate/with/slashes? (lambda (v) (and (even? v) (> v 4))))
> predicate/with/slashes?

#<procedure:predicate/with/slashes?>

> (define obscure-name-!$%^&*-_=+<.>/? "a string")
> obscure-name-!$%^&*-_=+<.>/?

"a string"

See also:

Identity🔗ℹ

Level: basic
Two objects are identical if they’re actually one and the same value. Given two objects, you can check whether they’re identical with the eq? function.

Examples:
; Obviously identical
> (define list1 '(1 2 3))
> (eq? list1 list1)

#t

; `list2` refers to the same list object.
> (define list2 list1)
> (eq? list1 list2)

#t

; `list3` and `list2` are _equal_, but not identical.
> (define list3 '(1 2 3))
> (eq? list1 list3)

#f

If the compared objects are immutable, it’s not that important if they’re identical. However, for mutable objects, modifications via one reference become visible in any other references to the same object:
; Changes in one vector are reflected in the "other" vector.
> (define vector1 (vector 1 2 3))
> (define vector2 vector1)
> (eq? vector1 vector2)

#t

> (vector-set! vector1 0 4)
> vector1

'#(4 2 3)

> vector2

'#(4 2 3)

; These vectors are equal, but not identical, so changes to one
; vector don't affect the other vector.
> (define vector3 (vector 1 2 3))
> (define vector4 (vector 1 2 3))
> (eq? vector3 vector4)

#f

> (vector-set! vector3 0 4)
> vector3

'#(4 2 3)

> vector4

'#(1 2 3)

Impersonator🔗ℹ

Level: advanced

Inexact number🔗ℹ

Level: basic
See Number

Inspector🔗ℹ

Level: advanced

Interface (API)🔗ℹ

Level: basic

Interface (OOP)🔗ℹ

Level: intermediate

Keyword🔗ℹ

Level: basic
Procedures can be defined and then called with positional arguments, but also with keyword arguments.

As an example, the following procedure takes a keyword argument to control whether an exclamation point should be added at the end of a greeting:

> (define (greeting name #:exclamation? exclamation?)
    (string-append
      "Hello "
      name
      (if exclamation?
          "!"
          "")))
> (greeting "Alice" #:exclamation? #f)

"Hello Alice"

> (greeting "Alice" #:exclamation? #t)

"Hello Alice!"

Like positional arguments, keyword arguments can be defined as optional:

> (define (greeting name #:exclamation? [exclamation? #f])
    (string-append
      "Hello "
      name
      (if exclamation?
          "!"
          "")))
> (greeting "Bob")

"Hello Bob"

It’s conventional to use the same name for the keyword and the argument name, but it’s not required.

Example:
> (define (greeting name #:exclamation? [exclamation-flag #f])
    (string-append
      "Hello "
      name
      (if exclamation-flag
          "!"
          "")))
> (greeting "Mike")

"Hello Mike"

> (greeting "Mike" #:exclamation? #t)

"Hello Mike!"

Note that the call uses the keyword name (#:exclamation?), but the function body uses the argument name (exclamation-flag).

If a function allows several keyword arguments, they can be specified in any order, and they can be interleaved with positional arguments. For example, consider the function ~r in the Racket standard library, which is used for formatting numbers:

> (~r 1.2345)

"1.2345"

> (~r 1.2345 #:precision 2)

"1.23"

> (~r #:precision 2 1.2345)

"1.23"

> (~r #:precision 2 1.2345 #:min-width 10)

"      1.23"

That said, usually the code is easier to read if all the positional arguments occur before all the keyword arguments:

> (~r 1.2345 #:precision 2 #:min-width 10)

"      1.23"

Racket clearly distinguishes between positional and keyword arguments. You can’t use a positional arguments in place of a keyword argument and vice versa:

> (define (greeting name #:exclamation? exclamation?)
    (string-append
      "Hello "
      name
      (if exclamation?
          "!"
          "")))
> (greeting "Bob" #:exclamation? #t)

"Hello Bob!"

> (greeting "Bob" #t)

greeting: arity mismatch;

 the expected number of arguments does not match the given

number

  expected: 1 plus an argument with keyword #:exclamation?

  given: 2

  arguments...:

   "Bob"

   #t

> (greeting #:name "Bob" #:exclamation? #t)

application: procedure does not expect an argument with

given keyword

  procedure: greeting

  given keyword: #:name

  arguments...:

   #:exclamation? #t

   #:name "Bob"

Other languages
Unlike Racket, many languages don’t have a clear distinction between positional and keyword arguments. For example, the following Python code is valid:

def greeting(name, exclamation):

    suffix = "!" if exclamation else ""

    return f"Hello {name}{suffix}"

 

greeting("Bob", exclamation=True)

See also:

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:189: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.

See also:

Lang (as in ‘#lang‘)🔗ℹ

Level: advanced

Language-oriented programming🔗ℹ

Level: advanced

Let🔗ℹ

Level: basic
Scheme and Racket support a variety of let forms.

The let form allows the definition of bindings that are valid for the body of let:
> (let ([x 2]
        [y 3])
    (+ x y))

5

However, it’s not possible to reference previous bindings as in
(let ([x 2]
      [y (add1 x)])
  (+ x y))

On the other hand, this is possible with the let* form:
> (let* ([x 2]
         [y (add1 x)])
    (+ x y))

5

You can think of let* as nested let forms, so the previous let* expression could be written as
> (let ([x 2])
    (let ([y (add1 x)])
      (+ x y)))

5

Still, let* doesn’t allow to access later bindings from earlier bindings as in
(let* ([y (add1 x)]
       [x 2])
  (+ x y))

On the other hand, this is possible with letrec. This form can be used to define mutually recursive functions (i.e. functions calling each other):
; These `even?` and `odd?` functions are only valid for n >= 0
> (letrec ([even? (lambda (n)
                    (if (= n 0)
                        #t
                        (odd? (sub1 n))))]
           [odd?  (lambda (n)
                    (if (= n 0)
                        #f
                        (even? (sub1 n))))])
    (even? 6))

#t

There’s also a “named let” form which uses the name let, but has the list of bindings prefixed with a name. Essentially, this form defines a – usually recursive – function and calls it. The result of the named let expression is the return value of the function call that started the recursion.

For example, defining and calling a recursive factorial function could look like this:
> (let factorial ([n 10])
    (if (= n 0)
        1
        (* n (factorial (sub1 n)))))

3628800

This is equivalent to
> (define (factorial n)
    (if (= n 0)
        1
        (* n (factorial (sub1 n)))))
> (factorial 10)

3628800

with the exception that for the named let form the factorial function is no longer accessible after the expression is calculated.

Here’s a summary of the different let forms:
  • let creates “parallel” bindings, i.e. the bindings can’t refer to each other.

  • let* creates nested bindings, i.e. later bindings can refer to earlier bindings.

  • letrec creates bindings where all bindings can refer to all others (even themselves).

  • A named let defines a function and calls it. The bindings specify the arguments for the initial call.

Racket has a few more let forms, in particular for handling multiple values. See the below sections in the Racket Guide and the Racket Reference.

See also:

Let over lambda🔗ℹ

Level: intermediate
“Let over lambda” describes a common idiom to create a closure. The following example is similar to the one in the Closure entry:
> (define add3
    (let ([increment 3])
      (lambda (value)
        (+ value increment))))
> (add3 5)

8

Here, let creates the outer environment whereas lambda defines the function using that environment.

See also:

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.

The reason why lists are still so widely used is that they make it easy to prepend items without changing the lists other references “see.” For example, the code
> (define list1 '(1 2 3))
> (define list2 (cons 'a list1))
> (define list3 (cons 'b (cdr list1)))
creates the following data structures:

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.

Example:
> (define list1 '(1 2 3 4))
> (define list2 (remove 2 list1))

creates the following structure:

Note that structure sharing depends only on the used list algorithms (e.g. in remove above). There’s no sophisticated algorithm that tries to “de-duplicate” common data. For example,
> (define list1 '(1 2 3))
> (define list2 '(1 2 3))
creates two separate list data structures.

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.

See also:

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.

Examples:
> (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
See Form

Match🔗ℹ

Level: intermediate

Match transformer🔗ℹ

Level: advanced

Method🔗ℹ

Level: intermediate

Module🔗ℹ

Level: basic

Named let🔗ℹ

Level: basic
See Let

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.

Additionally, there are some widely-used naming patterns:

Pattern

 

Meaning

 

Examples

name?

 

Predicate (1)

 

string?, null?

name=?

 

Comparison predicate (1)

 

string=?

name/c

 

Contract predicate (1)

 

or/c, one-of/c

name!

 

Mutation

 

set!, vector-set!

name*

 

Repetition

 

regexp-replace* vs. regexp-replace

name*

 

Nesting

 

for* vs. for

name*

 

Other variant

 

vector*-length vs. vector-length

name%

 

Class name

 

frame%

part/part

 

“for” or “with”

 

call/cc, define/match,
for/fold/derived

type->other-type

 

Conversion

 

vector->list

make-type

 

Create new value of type

 

make-base-namespace, make-channel

(1) Since the ? or /c suffix already identifies a predicate, using prefixes like “is-”, “has-” etc. is redundant.

See also:

Number🔗ℹ

Level: basic
Racket and most Scheme implementations have the following number types:
  • integer

  • rational

  • real

  • complex

However, these names can mean different things in different contexts. To understand the differences, it’s useful to view the number types under a “technical” and a “mathematical” aspect.

“Technical” number types

Integer and rational numbers are called exact because they can use arbitrarily many digits for calculations and therefore aren’t affected by rounding errors (as long as operations involve only exact values, of course). Float values are called inexact because many float operations lead to rounding errors.

A complex number is exact if both the real and the imaginary part are exact, otherwise the complex number is inexact.

The following diagram shows the relationships between the technical types.

“Mathematical” number types

Racket and many Scheme implementations have the predicates
However, these predicates don’t test for the technical types with the same or similarly-named types described above. Instead, the predicates work in a mathematical sense.

Examples:
; 2.0 is the same as the integer 2.
> (integer? 2.0)

#t

; 1.23 is mathematically the same as 123/100, which is a
; rational (and a real) number.
> (rational? 1.23)

#t

> (real? 1.23)

#t

; However, special values like `+inf.0` are `real?`, but not
; `rational?`.
> (rational? +inf.0)

#f

> (real? +inf.0)

#t

; All integer and real values are also complex values.
> (complex? 2)

#t

> (complex? 2.0)

#t

> (complex? 1.23)

#t

> (complex? +inf.0)

#t

; Numbers with a non-zero imaginary part are obviously
; complex values.
> (complex? 1+2i)

#t

Type notions combined

In Racket discussions, “integer” is usually understood as the technical type, i.e. an exact integer. Use “exact integer” as an exact wording. ;-) For the technical floating point type the term “float” avoids ambiguities with the mathematical “real” type.

You can express the technical types in terms of the mathematical predicates if necessary (v means “value”):

Technical type

 

Predicate combination

integer

 

(and (exact? v) (integer? v)) = (exact-integer? v)

rational

 

(and (exact? v) (not (integer? v)))

float

 

(and (inexact? v) (real? v)) = (inexact-real? v)

complex

 

(and (complex? v) (not (real? v)))

exact complex

 

(and (exact? v) (complex? v) (not (real? v)))

inexact complex

 

(and (inexact? v) (complex? v) (not (real? v)))

Tips and gotchas

See also:

Numeric tower🔗ℹ

Level: basic
The numeric tower, sometimes called “numerical tower,” is an analogy for how the “mathematical” number types include each other (see Number):

For example, for every number for which rational? gives #t, real? and complex? also give #t.

You could add “number” as the bottom of the tower, but at least in Racket, number? is equivalent to complex?.

See also:

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.

Usually a pair is created with cons:
> (cons 1 "one")

'(1 . "one")

Once a pair is created, you can access the first and second value of the pair with car and cdr:
> (define a-pair (cons 1 "one"))
> (car a-pair)

1

> (cdr a-pair)

"one"

See also:

Parameter🔗ℹ

Level: basic
Apart from the meaning in function definitions, a Racket parameter is a thread-local variable. A few examples are current-output-port, current-command-line-arguments and current-environment-variables.

To create custom parameters, use the make-parameter function. The value of the parameter is accessible by calling the created parameter function without arguments:
; The `make-parameter` argument is the initial value.
> (define new-parameter (make-parameter 3))
> (new-parameter)

3

You can set a parameter by calling the parameter function with an argument:
> (new-parameter 4)
> (new-parameter)

4

However, normally you should use the parameterize form to change the parameter value temporarily:
> (new-parameter)

4

> (parameterize ([new-parameter 5])
    (new-parameter))

5

> (new-parameter)

4

Using parameterize makes it clearer where the parameter value is changed. Another advantage is that the original parameter value is also restored if the body of parameterize raises an exception.

See also:

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.

For example, if you have a function curry that does the initial currying, the draw-line example above could become
> (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)

Racket has a function curry, which supports both partial application and currying at the same time.
> (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

See also:

Pattern (in regular expressions)🔗ℹ

Level: basic

Pattern (in macro definitions)🔗ℹ

Level: intermediate

Phase🔗ℹ

Level: advanced

Place🔗ℹ

Level: advanced

Polymorphism🔗ℹ

Level: intermediate

Port🔗ℹ

Level: basic
Basics

A port represents an input or output channel; ports correspond to file handles or file objects in other programming languages.

Using a port typically involves three steps:
  1. Create a port for input or output.

  2. Read data from the port or write data to the port, depending on whether the port was created for input or output. You can read or write data as strings, characters or bytes or a mixture of them, regardless of how you created the port.

  3. Close the port.

The ports for standard input, standard output or standard error already exist on program start, so there’s no need to create them. Also, you shouldn’t close any of these ports.

How do you use these special ports? Normally, you don’t need to specify them since they’re the default port arguments of functions like display or read-line.

Here are a few useful applications of the above three steps:

The examples above describe only the basic use cases. Racket has many more functions to read and write data as strings, characters or bytes. More on that below.

There are also a few functions that close the port implicitly. For example, the first code snippet could be written as
(call-with-input-file*
  "data.txt"
  (lambda (input-port)
    (port->string input-port)))
The function call-with-input-file* implicitly closes the input port, even if an exception occurs in the lambda.

Port types

The most important port types are
  • File ports. Created by functions like open-input-file and open-output-file.

  • String ports. Created by open-input-string and open-output-string. They’re useful if an API requires a port, but you already have the data in memory (instead of, say, a file). You can read the data accumulated in the output string with get-output-string.

  • TCP connections. Used for network connections. For example, tcp-connect connects to a host and port and returns an input port and an output port.

  • Process pipes. For example, the subprocess function can create ports for communication with its launched process.

You might also see the term “file stream ports.” It refers to both file ports and process pipes.

Port parameters

Racket provides the parameters current-input-port, current-output-port and current-error-port. At program start, these parameters correspond to standard input, standard output and standard error, respectively.

As usual with parameters, you can change them temporarily with parameterize, so the following example would write the output to an output file instead of to the terminal:
(parameterize ([current-output-port (open-output-port "data.txt")])
  (displayln "This goes to the file."))
This works because displayln outputs to current-output-port by default.

Function overview

Here are some Racket functions that work with input and output ports.

Creating ports

Port type

 

Input

 

Output

File

 

open-input-file

 

open-output-file

 

open-input-output-file

 

call-with-input-file* (1)

 

call-with-output-file* (1)

 

with-input-from-file (2)

 

with-output-to-file (3)

String port

 

open-input-string

 

open-output-string (4)

TCP connection

 

tcp-connect (5)

 

tcp-accept (6)

Process pipe

 

subprocess (7)

(1) The created port is passed to the proc argument. After executing proc, the file is closed, even if there was an exception in the proc.

(2) The created port is installed as current-input-port. After executing the thunk argument, the file is closed, even if there was an exception in the thunk.

(3) The created port is installed as current-output-port. After executing the thunk argument, the file is closed, even if there was an exception in the thunk.

(4) The current string value can be queried with get-output-string.

(5) For network clients. Returns an input port and an output port as two values.

(6) For network servers. Returns an input port and an output port as two values. Used with tcp-listen.

(7) If the arguments stdin, stdout and stderr are passed as #f, subprocess creates and returns new corresponding input and output ports.

Reading from and writing to ports

Data type

 

Input

 

Output

String

 

read-string

 

write-string

 

read-line

 

displayln

 

in-lines (1)

 

 

port->string

 

 

port->lines

 

Char

 

read-char

 

write-char

Byte string

 

read-bytes-line

 

write-bytes

 

in-bytes-lines (2)

 

Byte

 

read-byte

 

write-byte

(1) Generates a sequence of strings (see Comprehension)

(2) Generates a sequence of byte strings (see Comprehension)

Closing ports

Input

 

Output

close-input-port

 

close-output-port

Tips and gotchas

See also:

Predicate🔗ℹ

Level: basic
A predicate is a procedure that takes one argument and returns a boolean.

Examples:

Predicates can be used on their own or as arguments for higher-order functions like filter or takef:
> (filter string? '(2 "foo" bar 7))

'("foo")

> (takef '(2 6 -4 3 5 4) even?)

'(2 6 -4)

If you have a procedure that’s “almost” a predicate, you can use partial application to turn it into a predicate.

Example:
> (define (greater-than-two? number)
    (> number 2))
> (filter greater-than-two? '(1 3 -1 5 2))

'(3 5)

; Equivalent: define an anonymous procedure.
> (filter
    (lambda (number)
      (> number 2))
    '(1 3 -1 5 2))

'(3 5)

See also:

Print🔗ℹ

Level: basic

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:

> (define (foo)
    add1 2)
> (foo)

2

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!"

See also:

Profiling🔗ℹ

Level: intermediate

Prompt🔗ℹ

Level: advanced

Provide🔗ℹ

Level: intermediate
See Module

Quasiquote and unquote🔗ℹ

Level: intermediate
A variant of quote is quasiquote, usually written as a backtick (`). At first sight, quasiquote behaves exactly as quote:
> '(+ 3 4)

'(+ 3 4)

> `(+ 3 4)

'(+ 3 4)

> 'map

'map

> `map

'map

However, different from quote, you can use unquote, usually written as a comma (,) inside quasiquote to “escape” the quoting. This is useful to write lists that include literals and expressions that should be evaluated:
> `(1 2 ,(+ 1 1 1))

'(1 2 3)

See also:

Quote🔗ℹ

Level: basic
Quoting with quote prevents a quoted expression from being evaluated. Compare
> (+ 3 4)

7

> '(+ 3 4)

'(+ 3 4)

> map

#<procedure:map>

> 'map

'map

A single apostrophe can be used instead of spelling out quote:
> (+ 3 4)

7

> '(+ 3 4)

'(+ 3 4)

> map

#<procedure:map>

> 'map

'map

Quoted literal values like numbers, strings, characters and booleans are the values themselves:
> '123

123

> '"foo"

"foo"

> '#\space

#\space

> '#t

#t

Typical use cases for quoting are writing symbols and lists of literals:
> 'truncate

'truncate

> '(1 2 3)

'(1 2 3)

> '("foo" "bar" "baz")

'("foo" "bar" "baz")

Pay attention to avoid “double quoting.” For example, assume you’ve originally written
> (list 1 2 'foo)

'(1 2 foo)

and try to simplify the list as
> '(1 2 'foo)

'(1 2 'foo)

With this change, you get an expression ''foo, which is not the same as 'foo:
> (define my-list '(1 2 'foo))
> (list-ref my-list 2)

''foo

> (equal? ''foo 'foo)

#f

Although the expression ''foo looks like foo “quoted twice,” it’s more complicated.

If you see an expression starting with two apostrophes, it’s most likely a bug.

See also:

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
See Module

Rule (in macros; probably other uses, which ones?)🔗ℹ

Level: intermediate

Safe operation🔗ℹ

Level: intermediate

Scheme🔗ℹ

Level: basic

Scope🔗ℹ

Level: basic

Scribble🔗ℹ

Level: intermediate

Sequence, stream, generator🔗ℹ

Level: intermediate
Sequences

A sequence is a value that can be iterated over in a comprehension (or other for form). For example, lists and hashes are sequences:
> (for/list ([item '(1 2 3)])
    item)

'(1 2 3)

> (for/list ([(key value) (hash 'a 1 'b 2)])
    (cons key value))

'((b . 2) (a . 1))

Sequences don’t have to be fixed-size containers. It’s also possible to create values on the fly, like with in-range,
> (for/list ([item (in-range 2 5)])
    item)

'(2 3 4)

and even create values infinitely, like with in-naturals:
; Limit the iterated-over values with a sequence of limited length,
; otherwise `for/list` would never finish.
> (for/list ([unused '(a b c d e)]
             [item (in-naturals)])
    item)

'(0 1 2 3 4)

You can use sequence? to check whether a value is a sequence:
> (sequence? '(1 2 3))

#t

> (sequence? (hash 'a 1 'b 2))

#t

> (sequence? (in-range 2 5))

#t

> (sequence? (in-naturals))

#t

; An integer n is equivalent to `(in-range n)`
> (sequence? 5)

#t

A useful feature of sequences as used in for forms, is that they’re evaluated on demand (“lazily”). This is especially visible in in-naturals, which would never finish if it was fully evaluated and then iterated over. (The iteration would never happen because the evaluation would take infinite time.)

Streams

In case you want to implement a lazy or even infinite sequence, the easiest approach often is a stream.

Stream operations are very similar to list operations:

List operation

 

Stream operation

 

Purpose of stream operation

list

 

stream

 

Create stream from the given items (which aren’t evaluated by default)

'() = null = empty

 

empty-stream

 

Create empty stream

null? = empty?

 

stream-empty?

 

Check if stream is empty

cons

 

stream-cons

 

Create stream from first item and another stream

car = first

 

stream-first

 

Evaluate and return first item of stream

cdr = rest

 

stream-rest

 

Return stream with all items but the first

map, filter, ...

 

stream-map, stream-filter, ...

 

Higher-level operations (not all list operations have a corresponding stream operation)

The functions stream and stream-cons are lazy, that is, they don’t evaluate their arguments immediately. The evaluation only happens when individual items are retrieved from the stream:
> (define a-stream
    (stream
      (begin (displayln "one") 1)
      (begin (displayln "two") 2)
      (begin (displayln "three") 3)))
; Implicit evaluation by `stream-first`
> (stream-first a-stream)

one

1

; No evaluation by `stream-rest`
> (stream-rest a-stream)

#<stream>

; The result of an evaluation is cached, so this call
; does _not_ display "one".
> (stream-first a-stream)

1

Since stream APIs are very similar to list APIs, you can easily convert many list algorithms to corresponding stream algorithms. For example, assume we want a function that returns an infinite stream of the squares of the natural numbers. Let’s start with a function that returns a list of squares.
> (define (squares-list)
    (let loop ([i 0])
      (if (> i 10)
          '()
          (cons (* i i) (loop (add1 i))))))
> (squares-list)

'(0 1 4 9 16 25 36 49 64 81 100)

Note that we use a hardcoded upper limit. We’ll remove it later, but if we didn’t have the check in this list algorithm, squares-list would never finish.

Now change '() to empty-stream and cons to stream-cons. These are the only list functions to convert in this example.
> (define (squares-stream)
    (let loop ([i 0])
      (if (> i 10)
          empty-stream
          (stream-cons (* i i) (loop (add1 i))))))
> (squares-stream)

#<stream>

> (stream->list (squares-stream))

'(0 1 4 9 16 25 36 49 64 81 100)

Since we want an infinite stream, remove the condition:
> (define (squares-stream)
    (let loop ([i 0])
      (stream-cons (* i i) (loop (add1 i)))))
> (squares-stream)

#<stream>

; Since the stream is infinite, use `stream-take` to limit
; the evaluation to the first 11 items.
> (stream->list (stream-take (squares-stream) 11))

'(0 1 4 9 16 25 36 49 64 81 100)

Streams are also sequences, so they can be used as-is in comprehensions:
> (sequence? (squares-stream))

#t

; Use a parallel `in-range` to limit the generated items.
> (for/list ([unused (in-range 11)]
             [item (squares-stream)])
    item)

'(0 1 4 9 16 25 36 49 64 81 100)

Generators

Generators are another way to create lazy and potentially infinite sequences. A generator definition looks similar to a lambda definition, but a yield call in a generator yields an item to the caller of the generator. When the next item is requested, the generator continues the execution after the latest yield. There can be any number of yields in a generator.

Example:
> (define a-generator
    (generator ()
      (yield 1)
      (yield 2)
      (yield 3)))
; Three items from the `yield`s.
> (a-generator)

1

> (a-generator)

2

> (a-generator)

3

; After that, the generator yields `(values)`.
> (a-generator)
> (a-generator)
; This can be checked with `call-with-values`.
> (call-with-values a-generator list)

'()

If you want to base a sequence on a generator, you can return a stop value after the yields and use in-producer:
> (define a-generator
    (generator ()
      (yield 1)
      (yield 2)
      (yield 3)
      ; Stop signal
      #f))
> (for/list ([item (in-producer a-generator #f)])
    item)

'(1 2 3)

Similarly, for our infinite squares sequence we could use
> (define squares-generator
    (generator ()
      (for ([i (in-naturals)])
        (yield (* i i)))))
> (sequence? (in-producer squares-generator #f))

#t

; Use a parallel `in-range` to limit the generated items.
> (for/list ([unused (in-range 11)]
             ; No stop value since we want an infinite sequence
             [item (in-producer squares-generator)])
    item)

'(0 1 4 9 16 25 36 49 64 81 100)

Other languages
  • Some Scheme implementations also have stream and/or sequence concepts, but the APIs and semantics may differ from Racket’s.

  • Racket generators are similar to Python’s generator functions, but there are a few differences. See the section Generators in the Racket Reference for details.

See also:

Set🔗ℹ

Level: intermediate

Shadowing🔗ℹ

Level: basic
Shadowing means that a binding prevents access to another binding with the same name in an enclosing scope.

For example, in
> (let ([x 2])
    (displayln x)
    (let ([x 3])
      (displayln x)))

2

3

the inner x binding (value 3) shadows the outer x binding (value 2).

See also:

Splicing🔗ℹ

Level: basic

SRFI🔗ℹ

Level: intermediate

Standard library🔗ℹ

Level: basic
Typically, everything that’s installed by the Racket distributions from the Racket download page is called the Racket standard library. Apart from what’s documented in the Racket Reference this includes, for example, the DrRacket IDE, the Scribble documentation tool and the Typed Racket library.

See also:

Stream🔗ℹ

Level: intermediate

String, character, byte string🔗ℹ

Level: basic
The string, byte string and character data types are used for text processing.

Strings and characters

Strings represent human-readable text; they’re what you likely want if you do text processing.

Examples:
; 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

A string consists of characters, which represent unicode code points:
; 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"

That said, usually you don’t need to deal with individual characters. Most string processing works on substrings rather than characters.

Byte strings, bytes and encodings

To convert a string to bytes that can be written to a file or sent over a network socket, the string needs to be encoded to a byte string:
; 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

Conversely, byte strings can be decoded to strings:
; 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.

A byte string consists of bytes. “Byte” isn’t a “real” data type, but just means integers from 0 to 255. You can see the bytes/integers in a byte string more clearly with bytes->list:
> (bytes->list encoded-string)

'(77 195 188 108 108 101 114)

Type relationships

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.

String functions

The previous paragraphs explained how the string and character data types in Racket are related. However, for most text processing you’ll be fine with functions that operate on strings. Here are a few of these functions (but also check out the others in Strings in the Racket Reference).

Caveats

As mentioned above, strings consist of unicode code points. Unicode is rather complex and subtle, so the following caveats are shared by programming languages whose strings consist of code points:
  • 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=?.

The above list may look intimidating, but it isn’t, as long as you don’t rely on wrong assumptions (e.g. that the same “character” is always expressed by the same code points). For example, you can safely split a string at newline characters or other ASCII separators like colons without applying any of the normalizations.

See also:

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.

Example:
> (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!

Example:
> (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

Note two things:
  • 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.

See also:

Symbol🔗ℹ

Level: basic
Symbols are a data type that doesn’t exist in most programming languages. Symbols are similar to strings:
> "a-string"

"a-string"

> 'a-symbol

'a-symbol

There are several differences, though:
  • 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.

Symbols occur naturally when processing Racket code as data.

Example:
> (define expr1 (+ 3 4))
> expr1

7

; Note the quote character, '
> (define expr2 '(+ 3 4))
; A list with the `+` symbol, 3 and 4.
> expr2

'(+ 3 4)

> (symbol? (car expr2))

#t

See also:

Syntactic form🔗ℹ

Level: basic
See Form

Syntax (different meanings)🔗ℹ

Level: intermediate

Syntax transformer🔗ℹ

Level: intermediate
See Form

Tail call🔗ℹ

Level: intermediate

Tail position🔗ℹ

Level: intermediate

Testing🔗ℹ

Level: basic

Thread🔗ℹ

Level: intermediate

Thunk🔗ℹ

Level: basic
A thunk is a function that takes no arguments. Thunks are typically used to evaluate some code conditionally or at a later time (“lazily”). For example, assume that we want a variant of the if form that prints whether it evaluates the first or the second branch. Defining verbose-if like

> (define (verbose-if condition true-branch false-branch)
    (if condition
      (begin
        (displayln "condition is true")
        true-branch)
      (begin
        (displayln "condition is false")
        false-branch)))
> (verbose-if (> 5 4)
              (displayln "yes")
              (displayln "no"))

yes

no

condition is true

doesn’t work because in the call of verbose-if both the true-branch and the false-branch are already evaluated before executing the body of verbose-if.

However, you can control the execution of the true-branch and the false-branch by turning them into thunks:

> (define (verbose-if condition true-branch false-branch)
    (if condition
      (begin
        (displayln "condition is true")
        (true-branch))
      (begin
        (displayln "condition is false")
        (false-branch))))
> (verbose-if (> 5 4)
              (lambda () (displayln "yes"))
              (lambda () (displayln "no")))

condition is true

yes

Note that you need to change both the function and the use of it.

Even if the thunks need data from the surrounding scope, you don’t need to define and pass arguments because the thunks still have access to that scope even if they’re executed in verbose-if:

> (define (call-verbose-if)
    (define true-string "yes")
    (define false-string "no")
    (verbose-if (> 5 4)
                (lambda () (displayln true-string))
                (lambda () (displayln false-string))))
> (call-verbose-if)

condition is true

yes

See also:

Transparent🔗ℹ

Level: basic
See Struct

Trust level🔗ℹ

Level: advanced

Trusted code🔗ℹ

Level: advanced

Typed Racket🔗ℹ

Level: advanced

Undefined🔗ℹ

Level: advanced

Unit🔗ℹ

Level: advanced

Unsafe operation🔗ℹ

Level: intermediate

Untrusted code🔗ℹ

Level: advanced

Value🔗ℹ

Level: basic

Values🔗ℹ

Level: basic
Different from most other languages, a function in Scheme and Racket can return multiple values. The most basic function that can do this is values:
> (values 1 2)

1

2

The output here consists of two values, the values passed to values. The result is not a compound value like a pair or a list. Along these lines, you can’t assign multiple return values to a single name:
> (define a-name (values 1 2))

result arity mismatch;

 expected number of values not received

  expected: 1

  received: 2

To assign several values at once, instead use define-values:
> (define-values (foo bar) (values 1 2))
> foo

1

> bar

2

The equivalent let form is let-values:
> (let-values ([(foo bar) (values 1 2)])
    (+ foo bar))

3

By far the most functions in the standard library return a single value. Some functions that return multiple values, apart from values, are split-at, drop-common-prefix and split-common-prefix.

If accidentally using multiple values instead of a single value somewhere, the error message can be confusing. This is most obvious with functions that accept an arbitrary number of arguments, for example list:
> (list)

'()

> (list 1)

'(1)

> (list 1 2)

'(1 2)

> (list (values 1 2))

result arity mismatch;

 expected number of values not received

  expected: 1

  received: 2

Therefore, if you get an exception about an arity mismatch, it might be that some code passed multiple values instead of a single value.

Other languages
Some documentation on other programming languages, for example Python, sometimes uses the term “multiple values” to mean a single compound value. This is different from the “multiple values” concept in Scheme and Racket.

Here’s a Python example:

def return_tuple():

    return 1, 2

 

result = return_tuple()

print(type(result))  # tuple

print(result[0])     # 1

print(result[1])     # 2

See also:

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.

Literal vectors can be written with a #( prefix. Items in literal vectors are automatically quoted. The following examples use the vector-ref function to retrieve an item at a given index.

Examples:
; 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>

Vectors can be mutable or immutable. Literal vectors and those created with vector-immutable are immutable. Vectors created with vector are mutable.

Examples:
> (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.

See also:

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.

Examples:
> (define foo 2)
> (void? (set! foo 3))

#t

> (void? (display ""))

#t

> (void?
    (cond
      [(= 1 2) #f]))

#t

Another curiosity is that you can’t enter the #<void> value in source code or the REPL. However, you can create the value with (void).

Other languages
Python has a value None, whose semantics are 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) as default and check the argument with void? if #f could be an actual value for the argument.

See also:

Will🔗ℹ

Level: advanced

Write🔗ℹ

Level: basic

Writer🔗ℹ

Level: advanced