Racket (programming language)

19 min read
Updated
Suggest editHistoryTalk
RawGraph

Last edited

Fact-checked

In review queue

Sources

22 citations

Revision

v2 · 3,788 words

Fact-checks are independent of edits: a reviewer re-verifies the article against its sources and stamps the date. How we verify

Racket is a general-purpose, multi-paradigm programming language in the Lisp family and a direct descendant of Scheme. It is dynamically typed by default, supports first-class functions, continuations, and a hygienic macro system, and is built around an unusual feature for a Lisp: each source file declares its own language with a #lang line at the top, which lets users build and ship their own dialects on top of the same compiler and runtime. The project started on January 26, 1995 at Rice University under Matthias Felleisen as PLT Scheme, and was renamed Racket on June 7, 2010, the day version 5.0 shipped, to signal that the system had moved well beyond standard Scheme.[1][4][5] Its central design slogan, from the 2015 Racket Manifesto, is that "Racket is a programming language for creating new programming languages."[21]

Racket is best known for two things. The first is its long career as a teaching language behind the textbook How to Design Programs and the DrRacket IDE used in introductory CS courses at Northeastern, Brown, Waterloo, and elsewhere.[7] The second is its role as a research vehicle for programming language design, where its emphasis on language-oriented programming has produced typed dialects, lazy dialects, solver-aided dialects, and dozens of domain-specific languages.[21] Today Racket is developed by a distributed group of researchers and contributors at Northeastern, Utah, Brown, Indiana, Waterloo, and elsewhere, and is released under the MIT and Apache 2.0 licenses.[3]

At a glance

FieldValue
ParadigmsMulti-paradigm: functional, imperative, object-oriented, logic, meta
FamilyLisp / Scheme
Typing disciplineDynamic by default, optional static typing via Typed Racket
First appearedJanuary 26, 1995 (as PLT Scheme)
Renamed RacketJune 7, 2010 (with version 5.0)
Designed byMatthias Felleisen and the PLT group
ImplementationRacket CS (default since v8.0, built on Chez Scheme)
File extensions.rkt, .rktl, .scrbl
LicenseMIT or Apache 2.0 (dual)
Websiteracket-lang.org

Where did Racket come from?

PLT Scheme (1995 to 2010)

The project traces to a single day. On January 25, 1995, on a flight, Cormac Flanagan asked Matthias Felleisen a question that became the founding prompt of the group: "If functional programming is that good, why is nobody using it?"[22] The next day, January 26, 1995, Felleisen and a core team (Shriram Krishnamurthi, Bruce Duba, Cormac Flanagan, and Matthew Flatt) met in Corky Cartwright's office at Rice University and committed to building a curriculum, a programming language, and supporting software to teach functional programming to novices.[22] Felleisen's stated goal at that meeting was to "build a curriculum, a programming language, and support software to use functional programming for teaching algebra."[22]

Within days Matthew Flatt put together the first virtual machine, MrEd, by stitching together libscheme, wxWidgets, and a few other free systems; the earliest documented release was version 0.7 on May 10, 1995.[22] From that base the group, including Flatt, Robby Findler, Shriram Krishnamurthi, and Cormac Flanagan, produced DrScheme, an editor and runtime aimed at students, alongside MzScheme, a command-line implementation with the same core. The umbrella name PLT Scheme came from the Programming Language Team, the research and pedagogy group Felleisen had organized around novice programmers.

The project grew steadily over the next fifteen years. Hygienic macros, the module system, contracts, and the language-level mechanism all arrived during the PLT Scheme era. By the late 2000s the system had drifted far enough from R5RS and R6RS Scheme, and added enough of its own features, that the Scheme name was starting to mislead users. The R6RS standard in particular pushed Scheme in a direction the PLT group did not want to follow, and there was no clean way to keep calling the system Scheme without inviting comparisons that did not really apply.

When was Racket renamed, and why?

On June 7, 2010, PLT Scheme was renamed Racket, on the same day version 5.0 shipped.[1][5] The release notes for version 5.0 framed the change as a signal that the system had outgrown the Scheme label, and that future development would be done under a name that did not promise standards conformance with a language whose direction the project disagreed with. As Felleisen later put it in Racket, Historically Speaking: "By 2010, our dialect of Scheme had evolved so much that we renamed it to Racket."[4] DrScheme became DrRacket, MzScheme became Racket, and the PLT brand survived in package names and in the team itself.

After the rename, the focus shifted increasingly toward language-oriented programming and toward the macro system as a way of building entire languages, not just libraries. Typed Racket, which had been published in 2008 by Sam Tobin-Hochstadt and Matthias Felleisen, matured into a usable production dialect.[8] New dialects appeared, including Lazy Racket, Hackett, and Rosette, and the #lang mechanism became central to how Racket code was structured.

The move to Chez Scheme

The original Racket virtual machine, retroactively called Racket BC ("before Chez" or "bytecode"), was a custom JIT-based implementation written largely in C. Starting around 2017 the team, led by Matthew Flatt, began rewriting the runtime on top of Chez Scheme, Kent Dybvig's high-performance Scheme compiler. Cisco had open-sourced Chez Scheme in 2016, which made the move possible.

The rewrite replaced about 200,000 lines of C code with around 150,000 lines of Scheme and Racket code.[12] The new implementation, called Racket CS, became the default in Racket 8.0 on February 13, 2021.[12] Racket BC remained available through a separate installer, mainly to support older code that depended on its FFI quirks. Racket CS ships with better generational and parallel garbage collection, faster startup, and a smaller maintenance burden, since the compiler is written in the same family of languages it compiles.[12]

What does Racket's language design look like?

Racket is a Lisp-1, which means functions and values share a single namespace. This is the same convention as Scheme and Clojure and the opposite of Common Lisp, which keeps separate namespaces for functions and ordinary variables. The Lisp-1 choice makes higher-order programming smoother because the same name f can refer to a function value without funcall or #' ceremony.

Like every Lisp, Racket is homoiconic: programs are written as nested S-expressions, and the same nested-list structure is what macros operate on. A short example:

#lang racket

(define (fact n)
  (if (= n 0)
      1
      (* n (fact (- n 1)))))

(fact 10) ; 3628800

The #lang racket line at the top is the part that does not look like ordinary Scheme. It declares which language to read the rest of the file in. racket is the kitchen-sink dialect with the full standard library; racket/base is a smaller subset; typed/racket adds static types; lazy makes evaluation lazy; scribble/base turns the file into a documentation source. Each #lang is itself a normal Racket module that can be installed via the package system, which means new languages are first-class users of the same tooling as ordinary code.

Macros and language-oriented programming

Racket's macro system extends Scheme's syntax-rules and syntax-case with syntax-parse, a pattern-matching language for syntax that includes integrated error messages and reusable syntax classes. Macros are hygienic by default, meaning identifiers introduced by a macro do not accidentally capture or conflict with identifiers in the surrounding code. This is the same property Scheme made standard with syntax-rules in 1986, but Racket extends it with control over hygiene when you actually need to break it.

The deeper claim Racket makes is that macros are not just for adding little features to an existing language. They are for building entire new languages. The 2015 Racket Manifesto states the thesis directly: "Racket is a programming language for creating new programming languages, so that programmers can tailor a language to fit their problem."[21] In practice, a #lang is a module that exports a reader and a set of macros, and the result is that the file under it gets a brand-new surface syntax and semantics. Racket has been used this way to build educational sublanguages (the various Beginning, Intermediate, and Advanced Student Languages used by How to Design Programs), typed dialects, lazy dialects, query languages, build systems, slideware, and book-publishing systems.[7][19] Matthew Butterick's book Beautiful Racket is a long worked example of building several small languages from scratch using these tools.[15]

A tiny taste of a macro:

#lang racket

(define-syntax-rule (unless test body ...)
  (if test (void) (begin body ...)))

(unless (> 1 2)
  (displayln "one is not greater than two"))

unless is not a primitive in Racket; this defines it as a one-line macro that expands to an if.

Contracts

Racket also ships with a contract system, originally designed by Findler and Felleisen, that lets you attach precondition and postcondition checks to functions and modules.[18] Contracts are first-class values and can be combined like other values. When a contract fails, the system blames a specific party (the function or its caller) rather than just printing a stack trace.[18] The contract work fed directly into Typed Racket, since the boundary between typed and untyped modules is implemented as automatically generated contracts.[8]

What is Racket's type system?

By default Racket is dynamically typed, with the usual Lisp behavior: any value can be stored in any variable, and type errors show up at runtime. This is the same model as Scheme, Clojure, and other dynamic Lisps.

For code that wants static types, the standard option is Typed Racket, a typed dialect that lives at typed/racket. Typed Racket was introduced by Sam Tobin-Hochstadt and Matthias Felleisen in their 2008 POPL paper The Design and Implementation of Typed Scheme, and it is one of the better-known industrial-strength gradual typing systems.[8] It is designed to be sound across the boundary between typed and untyped modules, with values passed between the two worlds wrapped in dynamically checked contracts.

Typed Racket includes recursive union types, parametric polymorphism, subtyping, and a feature called occurrence typing, which refines a value's type within a branch based on a type predicate. For example:

#lang typed/racket

(: greet (-> (U String #f) String))
(define (greet name)
  (if (string? name)
      (string-append "hello, " name)
      "hello, stranger"))

Inside the if branch, name is narrowed from (U String #f) to String, so string-append typechecks without an explicit cast. The follow-up paper Logical Types for Untyped Languages (Tobin-Hochstadt and Felleisen, 2010) gave the formal account of how this works.[9]

A decade after the original paper, the same authors published Migratory Typing: Ten Years Later (2017), reflecting on what worked and what did not.[10] One recurring finding was that soundness comes at a real cost when typed and untyped code mix heavily, since contract checks at module boundaries can dominate runtime; Is Sound Gradual Typing Dead? (Takikawa et al., POPL 2016) measured this in detail.[11] Subsequent Typed Racket work has focused on reducing those overheads.

Implementation

Racket today has two implementations that share most of the same surface language:

ImplementationStatusNotes
Racket CSDefault since 8.0 (February 13, 2021)Built on Chez Scheme; faster, parallel garbage collection, easier to maintain
Racket BCLegacy, available via separate installerOriginal C-based VM with custom JIT; kept for compatibility

Both implementations compile through the same expander, which is itself written in Racket, so a #lang defined in one works in the other.[12] The expander, written by Matthew Flatt and known as the "new" or bootstrapped expander, is one of the larger pieces of Racket-in-Racket and the step that made the Chez migration possible: once the expander was self-hosting, the choice of underlying runtime became swappable.

DrRacket

DrRacket, formerly DrScheme, is the official IDE. It is itself a Racket program. The interface has two panes: a definitions window for editing source, and an interactions window that doubles as a REPL. The IDE understands the #lang line of the open file and switches its behavior accordingly: hitting Run on a #lang typed/racket file gets you the Typed Racket type checker; opening a Beginning Student Language file restricts the available primitives and syntax to the subset matching a given chapter of How to Design Programs.[7]

Features that are unusual for a beginner-focused IDE include a stepper that shows substitution-based reduction one step at a time (used heavily in introductory courses), a graphical syntax-error highlighter that draws arrows from binding to use, integrated check-syntax for tracking variable scope, an algebraic stepper, and tight integration with the macro expander so that you can step through a macro expansion the way you might step through a function call. DrRacket also doubles as a research IDE for the language-design work the PLT group does, since modifications to the expander and reader are visible inside the same environment that students use.

What is Racket used for in teaching?

A significant fraction of Racket's user base touches the language through a CS course or a curriculum, not through industry. Two efforts in particular are worth singling out.

How to Design Programs (HtDP), by Matthias Felleisen, Robert Bruce Findler, Matthew Flatt, and Shriram Krishnamurthi, was first published by MIT Press in 2001, with a second edition in 2018 that is freely available online.[7] The book teaches a systematic approach called the design recipe, a six-step process from data definitions through templates to function bodies and tests. It does not use the full Racket language. Instead it uses a sequence of teaching languages (Beginning Student, Beginning Student with List Abbreviations, Intermediate Student, Intermediate with Lambda, Advanced Student) that grow in expressive power as the student progresses. The teaching languages are themselves built using the #lang mechanism. HtDP underlies introductory courses at Northeastern, Brown, the University of Waterloo, the University of British Columbia, and other places.[6]

The Bootstrap curriculum, started by Emmanuel Schanzer in 2005 with Kathi Fisler at WPI and Shriram Krishnamurthi at Brown, takes a similar approach but pushes it down into middle and high schools.[16] Bootstrap:Algebra teaches students to write a small video game while simultaneously covering linear functions, function composition, the Pythagorean theorem, piecewise functions, and other topics from a standard algebra curriculum.[17] The programs are written in a teaching subset of Racket, and the curriculum has been used in over 150 schools in the United States.[16]

Ecosystem

The Racket ecosystem is small compared to mainstream languages, but it is reasonably complete. The package manager is invoked through raco, which is the umbrella command-line tool for everything that is not the language proper:

CommandPurpose
raco pkg install/update/removePackage management
raco makeAhead-of-time bytecode compilation
raco exeBuild a standalone executable
raco docOpen the local documentation
raco testRun a test suite
raco scribbleBuild documentation from Scribble sources

Packages live in a central catalog at pkgs.racket-lang.org, but a package source can also be a Git repository or a zip file. There is no version pinning beyond what a Git ref or a release file gives you, and the catalog is more of a name-to-source map than a content host.

A non-exhaustive list of well-known Racket projects:

ProjectAuthor(s)Description
Typed RacketTobin-Hochstadt, Felleisen, othersStatically typed dialect
RosetteEmina Torlak, Rastislav BodikSolver-aided language for synthesis and verification, built on Z3
HackettAlexis KingHaskell-like language with Racket macros
PollenMatthew ButterickPublishing system used to write Practical Typography and Beautiful Racket
FrogGreg HendershottStatic blog generator
ScribblePLTDocumentation language used for the Racket reference and HtDP itself
Lazy RacketPLTCall-by-need variant
FrTimePLTFunctional reactive variant

Scribble deserves a separate mention. It is the documentation language that the Racket reference, the Racket guide, and a long list of third-party manuals are written in. Pollen is in turn built on Scribble, which is the kind of layered DSL stack that the #lang system is designed to encourage.

How does Racket differ from other Lisps?

Racket sits in the same family as several other Lisps, and the differences are easier to see side by side.

FeatureRacketSchemeCommon LispClojure
NamespacesLisp-1Lisp-1Lisp-2Lisp-1
Standard sizeLarge, batteries-includedSmall, minimalistLarge, ANSI standardMedium, hosted on JVM
Macro hygieneHygienic, with syntax-parseHygienic since R5RSdefmacro, not hygienic by defaultMostly hygienic via gensym/#'
TypingDynamic plus optional static (Typed Racket)DynamicDynamic, with optional declarationsDynamic, plus core.typed and Spec
ConcurrencyThreads, places, futuresImplementation-definedImplementation-definedSTM-influenced reference types
Host platformNative (Chez) or BCManyManyJVM, JS, .NET via ports
Distinctive feature#lang and language-oriented programmingMinimalism, continuationsMacros and CLOS object systemJVM interop, persistent data structures

If you already know Scheme, most of Racket will feel familiar, with two big additions: the #lang mechanism and the much larger standard library. If you come from Common Lisp, the absence of CLOS in the same form will feel odd, although Racket has its own object system. If you come from Clojure, the static-typing story is very different (Typed Racket is more sound-by-construction than core.typed) and the host story is the inverse: Racket runs on its own runtime rather than on the JVM.

Is Racket relevant to AI and PL research?

Racket has been a workhorse for programming language research, especially around macros, gradual typing, and contracts. The volume of POPL, ICFP, and PLDI papers using Racket as either object of study or implementation vehicle is large, and several techniques that are now common in mainstream languages, like sound gradual typing and structural contracts, were prototyped in Racket first.[10][11]

The relevance to AI is mostly indirect, through two channels. The first is program synthesis and formal verification, both of which connect to the idea of generating or checking programs against specifications, which is also what large language model code assistants try to do, just by very different means. Rosette, designed by Emina Torlak and Rastislav Bodik and described in the 2013 Onward! paper Growing Solver-Aided Languages with Rosette, is a Racket-based language that compiles programs to logical constraints solved by SMT solvers like Z3.[13][14] Rosette has been used to build verifiers and synthesizers for new languages by writing an interpreter and letting the solver do the heavy lifting, which complements LLM-based program generation rather than competing with it. Sketch, designed by Armando Solar-Lezama, is the original syntax-guided synthesis system; while Sketch itself is not in Racket, the synthesis-by-sketching idea has been re-implemented and extended in Rosette.

The second channel is education. A non-trivial fraction of programming language researchers, including some who work on formal methods, type theory, and synthesis at AI-adjacent labs, learned to think about programs through How to Design Programs.[7] The design-recipe approach, the emphasis on data definitions and templates, and the use of contracts to specify behavior are all habits that show up in research code regardless of the language it ends up in.

This influence is real but easy to overstate. Racket is not a meaningful target for industrial machine-learning workloads, has no GPU story to speak of, and is not on the shortlist of languages that LLM code assistants are tuned for. Its place in an AI Wiki is as a notable Lisp dialect with a serious teaching tradition and a research community that overlaps with the formal-methods side of computer science.

Notable users and projects

Racket has not been a fixture of mainstream commercial software, but it has been used in several visible places. In academia, Racket is used in production in courses at Northeastern (Felleisen's group), Brown (Krishnamurthi), the University of Utah (Flatt), Indiana University (Tobin-Hochstadt), the University of Waterloo, and Worcester Polytechnic Institute (Fisler), among others.[6] Pollen, the publishing system, has been used to produce several professionally typeset books, including Matthew Butterick's Practical Typography and Typography for Lawyers.[15] The Racket reference manual itself is one of the longest documents written in Scribble.

ELI5: What is Racket?

Imagine a box of LEGO that does not just let you build models, but also lets you invent brand-new kinds of LEGO bricks and then build with those. Racket is a programming language that is great at making other little programming languages. You can write a normal program in it, like one that prints the numbers 1 to 10. But you can also write your own mini-language for, say, drawing pictures or making a game, and then write programs in that. That is why teachers love it (students learn step by step with simpler versions of the language) and why language researchers love it (they can try out new language ideas quickly).

See also

References

  1. Racket project. "Racket Documentation." https://docs.racket-lang.org/
  2. Racket project. "Download Racket." https://download.racket-lang.org/
  3. Racket project. "Software License." https://download.racket-lang.org/license.html
  4. Felleisen, Matthias. "Racket, Historically Speaking." https://felleisen.org/matthias/manifesto/Racket__Historically_Speaking.html
  5. Wikipedia. "Racket (programming language)." https://en.wikipedia.org/wiki/Racket_(programming_language)
  6. Wikipedia. "How to Design Programs." https://en.wikipedia.org/wiki/How_to_Design_Programs
  7. Felleisen, M., Findler, R. B., Flatt, M., Krishnamurthi, S. *How to Design Programs*, 2nd ed., MIT Press, 2018. https://htdp.org/
  8. Tobin-Hochstadt, S. and Felleisen, M. "The Design and Implementation of Typed Scheme." POPL 2008. https://www2.ccs.neu.edu/racket/pubs/dissertation-tobin-hochstadt.pdf
  9. Tobin-Hochstadt, S. and Felleisen, M. "Logical Types for Untyped Languages." ICFP 2010. https://www2.ccs.neu.edu/racket/pubs/icfp10-thf.pdf
  10. Tobin-Hochstadt, S., et al. "Migratory Typing: Ten Years Later." SNAPL 2017. https://www2.ccs.neu.edu/racket/pubs/typed-racket.pdf
  11. Takikawa, A., et al. "Is Sound Gradual Typing Dead?" POPL 2016. https://www2.ccs.neu.edu/racket/pubs/popl16-tfgnvf.pdf
  12. Racket Blog. "Racket Compiler and Runtime Status: January 2021." https://blog.racket-lang.org/2021/01/racket-status.html
  13. Torlak, E. and Bodik, R. "Growing Solver-Aided Languages with Rosette." Onward! 2013. https://homes.cs.washington.edu/~bodik/ucb/Files/2013/onward13.pdf
  14. Rosette project. "Rosette: About." https://emina.github.io/rosette/
  15. Butterick, M. *Beautiful Racket*. https://beautifulracket.com/
  16. Bootstrap project. https://www.bootstrapworld.org/
  17. Wikipedia. "Bootstrap curriculum." https://en.wikipedia.org/wiki/Bootstrap_curriculum
  18. Findler, R. B. and Felleisen, M. "Contracts for higher-order functions." ICFP 2002.
  19. Flatt, M. "Creating Languages in Racket." *ACM Queue*, 2011. https://queue.acm.org/detail.cfm?id=2068896
  20. Racket GitHub repository. https://github.com/racket/racket
  21. Felleisen, M., Findler, R. B., Flatt, M., Krishnamurthi, S., Barzilay, E., McCarthy, J., Tobin-Hochstadt, S. "The Racket Manifesto." SNAPL 2015, LIPIcs Vol. 32, pp. 113-128. https://www2.ccs.neu.edu/racket/pubs/manifesto.pdf
  22. Racket Blog. "Racket is 25." May 2020. https://blog.racket-lang.org/2020/05/racket-is-25.html

Improve this article

Add missing citations, update stale details, or suggest a clearer explanation. Every suggestion is reviewed for sourcing before it goes live.

1 revision by 1 contributors · full history

Suggest edit