Racket is a general-purpose, multi-paradigm programming language originating from the Lisp/Scheme family. Developed initially as PLT Scheme, it was renamed Racket in 2010 to emphasize its focus on language-oriented programming and macro-based extensibility. The language features a rich macro system, a powerful module system, and a large standard library. It is widely used in education, research, and practical software development, particularly for creating domain-specific languages (DSLs) and as a platform for exploring language design.

1 History

1.1 Origins as PLT Scheme

Racket began in the mid-1990s as PLT Scheme, a research-oriented implementation of the Scheme programming language. The project was led by Matthias Felleisen and others at Rice University and later at Northeastern University. PLT Scheme aimed to provide a robust platform for teaching programming (notably through the *How to Design Programs* curriculum) and for exploring language design. The system included a graphical IDE (DrScheme), a rich set of libraries, and a novel module system. Over time, the implementation diverged from standard Scheme by adding features such as a powerful macro system (hygienic macros) and practical tools for building new languages.

1.2 Renaming to Racket (2010)

In 2010, the PLT Scheme team announced that the language would be renamed Racket. The new name reflected the project's broader ambition: a *racket* of languages, i.e., a platform where users can compose and extend languages. The name change also distanced the language from the traditional Scheme standard, emphasizing its unique identity. Version 5.0 was the first release under the Racket name, and the DrScheme IDE was renamed DrRacket.

1.3 Major version milestones

  • Version 5.0 (2010): Rename to Racket; introduction of the #lang syntax for language-oriented programming.
  • Version 5.1–5.3 (2011–2012): Major improvements to the macro system, including syntax-parse.
  • Version 6.0 (2014): Gradual typing system (Typed Racket) reaches maturity; new package manager (raco pkg).
  • Version 7.0 (2018): Rewritten expander based on a new “macro‑engine” design; improved performance.
  • Version 8.0 (2020): Enhanced support for Chez Scheme backend; faster compilation and execution.
  • Version 8.x (2021–2024): Continuous updates to libraries, tooling, and documentation.

2 Core Language Features

2.1 Syntax and S-expressions

Racket uses S-expressions (symbolic expressions) as its surface syntax, inherited from Lisp. An S-expression is either an atom (number, string, symbol, etc.) or a list of S-expressions enclosed in parentheses. This uniform syntax simplifies parsing and is especially amenable to macro manipulation. Racket extends S-expressions with square brackets ([ ]) and curly braces ({ }) for stylistic convenience; they are treated identically to parentheses.

2.2 First-class procedures and closures

Procedures (functions) in Racket are first-class values: they can be passed as arguments, returned from other functions, and stored in data structures. Racket closures capture the lexical environment, enabling standard functional‑programming patterns such as higher-order functions and callbacks. The language supports both eager and lazy evaluation (via explicit constructs), but defaults to eager.

2.3 Immutable data structures

Racket emphasizes immutability. Most core data structures—lists, vectors, hash tables, and strings—have immutable variants. Mutable versions exist when needed (e.g., mutable hash tables, vectors), but immutable forms are the default and are preferred for safety and reasoning. Immutable pairs (cons), for example, cannot be modified after creation.

2.4 Contract system

Racket’s contract system allows programmers to specify and enforce behavioral agreements between different parts of a program. Contracts are like assertions attached to functions, classes, or modules, checking values at runtime. They support property‑based specifications (e.g., “this function returns a positive integer”) and can be integrated with the macro system for compile‑time enforcement. Contracts are a key element of Racket’s design for building reliable software.

3 Macro System

3.1 Hygienic macros

Racket’s macro system is hygienic: macros automatically avoid accidental variable capture (unintended name collisions between macro-generated code and surrounding code). This is achieved via a sophisticated system of lexical scope markers, called *syntax objects*, which carry source location and binding information. Hygienic macros in Racket are more powerful and safer than traditional Lisp macros.

3.2 Syntax transformers

Syntax transformers are the mechanism that rewrites source code during compilation. A macro in Racket is a procedure that takes a syntax object (representing the macro call) and returns a new syntax object (the expanded form). The macro writer uses functions like syntax and quasisyntax to construct code patterns, and syntax-case or syntax-parse to destructure the input. The transformer runs at compile time, allowing arbitrary computation during the macro expansion phase.

3.3 Macro-writing utilities (syntax-parse, syntax-rules)

Racket provides several utilities for writing macros:

  • syntax-rules: A simple, declarative macro system based on pattern matching. It is suitable for straightforward syntactic abbreviations and enforces hygiene automatically.
  • syntax-case: A low-level macro form that gives full control over syntax objects. It allows pattern matching with arbitrary predicates and the ability to break hygiene deliberately (using datum->syntax) when needed.
  • syntax-parse: An advanced macro‑writing library that extends syntax-case with richer pattern matching, automatic attributes, and error reporting. It is the preferred tool for complex macros in modern Racket code.

3.3.1 Pattern-based macros

Pattern-based macros are written using syntax-rules or syntax-parse. A macro definition consists of one or more clauses, each containing a pattern and a template. When the macro use matches a pattern, the corresponding template is expanded. For example:

(define-syntax-rule (my-when test body ...)
  (if test (begin body ...)))

This is a simple pattern-based macro that translates (my-when condition (do-something)) into an if form.

3.3.2 Low-level macro API

For advanced use, Racket exposes the full low-level API for syntax objects. This includes functions such as:

  • syntax-e: Extract the datum from a syntax object.
  • datum->syntax: Create a syntax object from a datum with specified lexical context.
  • syntax-local-introduce and syntax-local-certifier: Manage hygiene and scope.
  • with-syntax: Bind pattern variables in a template.

These primitives are rarely used directly; instead, libraries like syntax/parse abstract over them.

4 Language-Oriented Programming

4.1 Defining new languages via #lang

Racket’s most distinctive feature is the ability to define and use new programming languages as easily as using standard ones. A file starting with #lang followed by a module name (e.g., #lang racket, #lang typed/racket, or a custom language) tells Racket which language to load. Language definitions are themselves Racket modules that export specific components: a reader, an expander, and runtime semantics. This creates a “language tower” where languages can inherit from others.

4.2 Language components: reader, expander, module runtime

A language in Racket is composed of three phases:

  • Reader: Converts source text into a sequence of S-expression‑like tokens (syntax objects). A custom reader can parse arbitrary syntax (e.g., infix notation, indentation-based blocks).
  • Expander: Transforms the parsed syntax into core Racket forms, typically using macros. The expander is responsible for all compile‑time evaluation and macro expansion.
  • Module runtime: Defines the runtime semantics of the language—how modules are loaded, linked, and executed. Most languages reuse Racket’s runtime, but custom runtimes are possible.

4.2.1 Custom reader syntax

The reader component can be overridden to parse non‑S‑expression syntax. For example, the #lang planet language allows curly braces and indentation, and #lang scribble uses a mixture of S‑expressions and text. The reader produces syntax objects with location information, which the expander then processes.

4.2.2 Module-level language semantics

Languages can specify how modules are organized and how they interact. For instance, #lang racket enforces strict module boundaries and explicit exports; #lang typed/racket adds type checking at the module boundary. A custom language might define dynamic scoping, or a file‑structuring system (e.g., sections and chapters in Scribble).

4.3 Example: Building a small DSL

A simple example of language‑oriented programming in Racket is creating a DSL for arithmetic expressions. One could define a language expr-lang that parses infix expressions and compiles them to Racket code. The reader would convert 3 + 4 * 2 into something like (3 + (4 * 2)); the expander would then transform those into calls to + and *. The language would be used by writing #lang expr-lang at the top of a file. This pattern is common in Racket projects for embedding small DSLs for configuration, templating, or problem‑specific notation.

5 Ecosystem and Tools

5.1 DrRacket IDE

DrRacket (formerly DrScheme) is the official integrated development environment for Racket. It features:

  • Syntax highlighting and parentheses matching.
  • A built-in REPL (“interactions window”) for testing.
  • A debugger, stepper, and profiler.
  • Integrated documentation and a “Check Syntax” tool that shows binding arrows.
  • Support for multiple language levels (from beginner to full Racket).

DrRacket is written in Racket itself and is extensible via plugins.

5.2 Package manager (raco)

raco is Racket’s command-line tool for managing packages, building executables, and performing other administrative tasks. The command raco pkg install installs packages from the Racket package catalog (pkg.racket-lang.org). raco also handles dependencies, updates, and uninstallation. Other raco commands include raco make (compiling bytecode), raco exe (creating standalone executables), and raco test (running tests).

5.3 Unit testing framework

Racket includes a built‑in unit testing framework, rackunit. It provides:

  • check-equal?, check-true, check-not-equal? and other check forms.
  • Test suites and stubs for modular testing.
  • Integration with DrRacket’s test runner and raco test.

Additionally, more advanced testing libraries like quickcheck (generative testing) are available as packages.

5.4 Debugging and profiling

Racket offers:

  • DrRacket debugger: Step through code line by line, inspect stack frames, and set breakpoints.
  • Stack trace analysis: On runtime errors, a detailed stack trace (with line numbers and binding information) is displayed.
  • Profiler: The raco profile command measures time and memory usage of Racket programs.
  • Contract failures: Runtime contract violations produce detailed error messages explaining which contract was violated and where.

6 Standard Libraries

6.1 Base library

The racket/base library provides the core language: procedures for arithmetic, list operations, control flow (if, cond, case, etc.), I/O primitives, and system functions. It is small and fast. The racket language (used via #lang racket) is the full standard library, which includes racket/base plus many additional modules.

6.2 Collections and I/O

Racket’s standard library includes a wide range of data structures: lists, vectors, hash tables, sets, queues, and sequences (lazy streams). The racket/sequence module provides a uniform interface for iteration. I/O libraries handle files, sockets, pipes, and ports, with support for encoding, buffering, and regular expressions. Racket also includes functions for serialization (racket/serialize) and reading/writing structured data.

6.3 Graphics and GUI (racket/gui)

The racket/gui library provides a platform‑independent graphical user interface toolkit. It includes classes for windows, buttons, text fields, menus, and drawing canvases. The drawing subsystem supports 2D graphics (lines, shapes, images) and is built on a simple model of “pictures” and “dc” (device context). Racket also has racket/draw for low‑level graphics and racket/slide for presentations.

6.4 Networking and web (racket/servlet)

Racket’s web server library (racket/servlet) allows building HTTP servers and web applications. It supports:

  • Stateless and stateful servlets (with automatic session management).
  • URL dispatch and template‑based page generation.
  • Form handling and cookie management.

The racket/net module provides lower‑level networking (TCP, UDP, SSL). Racket also includes an HTML‑to‑S‑expression parser and a JSON parser/generator.

7 Typed Racket

7.1 Gradual typing system

Typed Racket is a statically typed variant of Racket that coexists with untyped Racket in the same program. It implements *gradual typing*: a type checker verifies annotated code, while untyped parts are left unchecked (with dynamic checks at boundaries). This allows programmers to add type annotations incrementally, starting from an untyped codebase and gradually tightening the type coverage.

7.2 Type inference and annotations

Typed Racket uses local type inference: the types of most expressions can be inferred, but function parameters and certain top‑level bindings require explicit annotations. Types include base types (Number, String, Boolean), compound types (Listof, HashTable), function types (→), union types (U), and polymorphic types (All, ∀). The type system supports dependent types for some structures (e.g., fixed‑size vectors) and occurrence typing (refining types based on predicates).

7.3 Interoperation with untyped code

Typed and untyped modules can be used together seamlessly. When a typed module imports from an untyped module, the typed module receives static types based on the untyped module’s defined exports (if any type information is provided via require/typed). Otherwise, the type checker treats the import as having the Any type. At runtime, contract wrappers are inserted at boundaries to ensure that values conform to expected types, providing a safety net. This hybrid approach is one of Racket’s distinguishing features.

8 Education and Research

8.1 Pedagogy (How to Design Programs)

Racket is the primary platform for the *How to Design Programs* (HtDP) textbook and curriculum, which teaches systematic program design principles. The language’s simplicity, strong pedagogical tools (DrRacket with student language levels), and emphasis on contracts and tests make it ideal for introductory programming courses. Many universities use Racket in their first‑year CS courses, especially for teaching functional programming and recursion.

8.2 Use in programming language research

Racket is a popular platform for programming language research. Its macro system and language‑oriented design allow researchers to quickly prototype new language features, type systems, and semantics. The ability to define small languages (via #lang) makes it possible to implement a new language and immediately test it with existing tools. Topics studied using Racket include gradual typing, contract systems, delimited continuations, and algebraic effects.

8.3 Notable academic projects

Several academic projects have been implemented in or influence Racket:

  • Scribble: A documentation‑generation language (used for the official Racket documentation).
  • Pict: A picture‑drawing DSL used for teaching graphics.
  • Rosetta: A system for building concurrent and distributed languages.
  • Turner’s DSLs: Many custom languages for teaching (e.g., #algol60, #fril).
  • Redex: A formal semantics‑engineering tool built on Racket, used for modeling programming languages and type systems.

9 Community and Resources

9.1 Official documentation and mailing lists

The official Racket documentation is extensive and well‑organized, available at docs.racket-lang.org. It includes reference manuals, tutorials, guides, and a searchable index. The primary mailing lists are the racket-users list (for general discussion and help) and the racket-dev list (for development). There is also an active IRC channel (#racket on Libera.Chat) and a Discourse forum.

9.2 Conferences (RacketCon)

RacketCon is the annual conference for the Racket community. It features talks on language development, tooling, case studies, and educational uses. RacketCon is usually held in the summer and is organized by the Racket core team and volunteers. Past events have included hands‑on workshops and hackathons.

9.3 Contributing to Racket

Contributions to Racket are welcome. The source code is hosted on GitHub (racket/racket). Contributors can submit bug reports, feature requests, or patches. The development process is documented on the Racket wiki, and there is a style guide for contributing to the standard libraries. The Racket core team also mentors new developers through the Google Summer of Code program.