Skip to content
Racket: A Language for Creating Languages

Racket: A Language for Creating Languages

DodaTech Updated Jun 20, 2026 6 min read

Racket is a general-purpose programming language and a platform for creating programming languages. It belongs to the Lisp/Scheme family and is used in education, research, and industry for building domain-specific languages (DSLs).

In this tutorial, you’ll learn Racket’s core concepts: its role as a language workbench, DrRacket IDE, parentheses syntax, macros for metaprogramming, contracts for runtime verification, and the teaching language suite.

What You’ll Learn

  • Racket as a language workbench (PL ideas)
  • DrRacket IDE features
  • Parentheses syntax and prefix notation
  • Macros — programs that write programs
  • Contracts for runtime assertions
  • Teaching languages (Beginning Student, Intermediate, Advanced)
  • Building a simple DSL

Why Racket Matters

Racket is used to create programming languages. The Pyret language, the Scribble documentation system, and the HtDP (How to Design Programs) curriculum all use Racket. At DodaTech, the macro system in Racket inspires metaprogramming patterns in DodaZIP’s template engine.

Learning Path

    flowchart LR
  A[Lisp Concepts] --> B[Racket Basics<br/>You are here]
  B --> C[Macros & Metaprogramming]
  C --> D[DSL Creation]
  B --> E[Contracts & Testing]
  style B fill:#f90,color:#fff
  

Parentheses and Prefix Notation

Racket uses prefix notation: the operator comes first, followed by arguments:

#lang racket

; Prefix notation
(+ 1 2 3)           ; 6
(* 2 3 4)           ; 24
(string-append "Hello" " " "World")  ; "Hello World"

; Nested expressions
(define (square x) (* x x))
(square 5)          ; 25

; Conditionals
(define (abs-val x)
  (if (negative? x)
      (- x)
      x))

(abs-val -10)  ; 10
(abs-val 5)    ; 5

; List operations
(define numbers '(1 2 3 4 5))
(map sqr numbers)        ; '(1 4 9 16 25)
(filter odd? numbers)    ; '(1 3 5)
(foldl + 0 numbers)      ; 15

Expected output: The REPL evaluates each expression and prints the result. Note that #lang racket tells Racket which language to use — you can swap it for any language you define.

DrRacket IDE

DrRacket is the official IDE with unique features:

FeaturePurpose
StepperStep through evaluation one reduction at a time
Syntax coloringParentheses matching with rainbow colors
REPLInteractive evaluation with history
RequireEasy module importing
Language selectorSwitch between student and professional languages

The stepper is invaluable for beginners — it shows exactly how expressions evaluate, revealing the substitution model.

Data Structures

Racket’s primary data structures:

#lang racket

; Lists (linked)
(define fruits '(apple banana cherry))
(first fruits)     ; 'apple
(rest fruits)      ; '(banana cherry)
(cons 'date fruits) ; '(date apple banana cherry)

; Vectors (fixed-size, O(1) access)
(define vec #(10 20 30))
(vector-ref vec 1)  ; 20
(vector-set! vec 1 25)
vec                  ; #(10 25 30)

; Hash tables
(define scores (make-hash))
(hash-set! scores 'alice 95)
(hash-set! scores 'bob 87)
(hash-ref scores 'alice)  ; 95

; Structures (like classes)
(struct point (x y) #:transparent)
(define p (point 3 4))
(point-x p)  ; 3
(point-y p)  ; 4

; Pattern matching
(match p
  [(point 0 0) "origin"]
  [(point x y) (format "(~a, ~a)" x y)])
; "(3, 4)"

Expected output: Each form evaluates to its result. Structures with #:transparent print their fields.

Macros — Programs That Write Programs

Macros transform code before evaluation. They’re Racket’s most powerful feature:

#lang racket

; Simple macro — infix notation
(require syntax/parse/define)

(define-syntax-rule (infix a op b)
  (op a b))

(infix 3 + 5)   ; 8
(infix 10 * 2)  ; 20

; More complex macro — conditional logging
(define-syntax (log-if-debug stx)
  (syntax-parse stx
    [(_ expr)
     #'(when *debug-mode*
         (printf "DEBUG: ~a => ~a~n" 'expr expr)
         expr)]))

(define *debug-mode* #t)
(log-if-debug (+ 1 2))
; DEBUG: (+ 1 2) => 3
; 3

Expected behavior: The log-if-debug macro expands to a when form that conditionally prints the expression and its value. In non-debug mode, the logging is removed entirely — zero runtime cost.

Contracts

Contracts are runtime assertions attached to functions via provide:

#lang racket

(provide
  (contract-out
    [divide (->i ([a number?] [b (and/c number? (not/c zero?))])
                 [result number?])]))

(define (divide a b)
  (/ a b))

; Usage — contract violation
; (divide 10 0)
; => divide: contract violation
;    expected: (and/c number? (not/c zero?))
;    given: 0

Contracts document and enforce function behavior at module boundaries — like types for untyped code.

Teaching Languages

Racket’s teaching languages scaffold learning:

LanguageFeaturesFor
Beginning StudentFunctions, numbers, strings, imagesAbsolute beginners
IntermediateLists, lambda, local definitionsLearning recursion
Advanced StudentMutation, vectors, structsTransition to professional
#lang beginner

; No mutation, no loops, no variables
; Everything is function application
(define (factorial n)
  (cond
    [(zero? n) 1]
    [else (* n (factorial (- n 1)))]))

(factorial 5)  ; 120

Common Mistakes

1. Forgetting #lang

Every Racket file must start with #lang racket (or another language). Without it, the reader doesn’t know what language to use.

2. Mismatched Parentheses

Racket highlights matching parentheses. Count them carefully. Use DrRacket’s auto-indent (Tab) to check nesting.

3. Confusing quote and quasiquote

'(1 2 3) is a literal list. `(1 ,(+ 1 2) 3) is quasiquote — the , unquotes for evaluation. Result: '(1 3 3).

4. Using set! Without Understanding Mutation

Mutation is available but discouraged. Prefer functional updates. set! changes a variable; set-car! changes a list cell.

5. Forgetting That Everything Is an Expression

if, cond, begin, let — all produce values. There’s no statement/expression distinction.

6. Not Using the Stepper

If your code doesn’t do what you expect, run the stepper. It shows every step of evaluation.

Practice Questions

1. What does #lang racket mean?

It tells Racket which language to use. Racket is a language workbench — you can use or define any language.

2. What is a macro?

A macro is a compile-time code transformation. Macros let you extend the language syntax and implement domain-specific languages.

3. What is a contract?

A runtime assertion attached via provide. Contracts enforce behavior at module boundaries, catching violations at the source.

4. What is the difference between car/cdr and first/rest?

They’re aliases. car/cdr are historical (from Lisp). first/rest are modern Racket. Use first/rest for readability.

5. Challenge: Write a macro that defines a simple loop.

Create a repeat macro: (repeat n body ...) that evaluates body n times.

Mini Project: Infix Calculator DSL

#lang racket

(define-syntax-rule (calc expr ...)
  (calc-helper 'expr expr) ...)

(define (calc-helper original result)
  (printf "~a = ~a~n" original result))

(calc
  1 + 2
  10 * 5
  (+ 1 (* 2 3)))
; 1 + 2 = 3
; 10 * 5 = 50
; (+ 1 (* 2 3)) = 7

FAQ

Is Racket a Lisp?
Yes. Racket descends from Scheme, which descends from Lisp. It uses prefix notation and has first-class macros.
What is Racket used for in industry?
DSL creation, web servers (Racket’s web server), education (How to Design Programs curriculum), and research in programming languages.
Is Racket fast enough for production?
Racket’s JIT compiler produces competitive performance. The web server benchmarks well. For CPU-bound work, Racket is slower than C/Rust but faster than Python/Ruby.

What’s Next

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro