Home

Racket Cheat Sheet

Lang Declaration

Every Racket file must start with a #lang directive specifying the language variant:

1#lang racket/base    ; Minimal core
2#lang racket         ; Standard library
3#lang at-exp racket  ; @ notation for string interpolation

Exports & Contracts

Contracts with exports (preferred pattern for library code):

1(provide (contract-out
2  [function-name (-> string? number? boolean?)]
3  [process-data (->* (string?) (number?) list?)]))  ; optional params

Simple exports (for internal code):

1(provide function-name
2         another-function)

Submodules

Test submodule - code only runs during raco test:

1(module+ test
2  (require rackunit)
3  (test-case "description"
4    (check-equal? (add 2 3) 5)))

Main submodule - entry point when file runs as script:

1(module+ main
2  (define args (current-command-line-arguments))
3  (start-app args))

Defining Racket Functions with Contracts

Basic Contracts

1; Simple function: string -> number -> boolean
2(define/contract (validate-input text count)
3  (-> string? number? boolean?)
4  (> (string-length text) count))

Optional Parameters

1; Required param, optional param, returns string
2(define/contract (format-message msg [prefix "Info"])
3  (->* (string?) (string?) string?)
4  (string-append prefix ": " msg))

Multiple Value Returns

1; Function returning two values
2(define (http-request url)
3  (values response-body status-code))
4
5; Consuming multiple values
6(define-values (body status) (http-request "http://api.example.com"))

Racket String Manipulation and Interpolation

String Interpolation with @-expressions

1#lang at-exp racket  ; Required in lang declaration
2
3(define api-key "abc123")
4(define url @string-append{
5  https://api.example.com/v1/data?key=@|api-key|&format=json
6})

Common String Functions

1(string-append "hello" " " "world")        ; Concatenation
2(string-join '("a" "b" "c") ", ")         ; Join list
3(string-split "a,b,c" ",")                ; Split to list
4(string-trim "  text  ")                  ; Trim whitespace
5(string-downcase "HELLO")                 ; Lowercase
6(string-replace "hello" "l" "L")          ; Replace
7(format "~a is ~a" name value)            ; Format string

String/Bytes Conversion

1; Critical for HTTP and crypto operations
2(string->bytes/utf-8 "text")              ; string -> bytes
3(bytes->string/utf-8 #"bytes")            ; bytes -> string

Core Data Structures: Lists & Hashes

Association Lists (alists)

Preferred for headers and key-value pairs:

 1; Creating
 2(define headers
 3  '(("Content-Type" . "application/json")
 4    ("Authorization" . "Bearer token")))
 5
 6; Accessing with case-insensitive comparison
 7(define (get-header name headers)
 8  (match (assoc name headers string-ci=?)
 9    [(cons _ value) value]
10    [_ #f]))

Hashes

 1; Immutable hash from alist
 2(define headers-hash
 3  (make-immutable-hash
 4    (map (λ (pr) (cons (string->symbol (car pr)) (cdr pr)))
 5         headers-alist)))
 6
 7; Hash operations
 8(hash 'key1 "value1" 'key2 "value2")      ; Create
 9(hash-ref h 'key)                          ; Get
10(hash-set h 'key "value")                  ; Set (immutable)

Pattern Matching

1; Match expressions for control flow
2(match result
3  ["success" (handle-success)]
4  ["error" (handle-error)]
5  [_ (handle-unknown)])
6
7; Destructuring
8(match (cons key value)
9  [(cons k v) (process k v)])

Parsing and Generating XML with X-expressions

X-expressions (xexpr)

S-expression representation of XML:

 1; xexpr format: (tag ((attr val) ...) child ...)
 2(define doc
 3  `(response
 4     (status ((code "200")) "OK")
 5     (data "content")))
 6
 7; Convert between formats
 8(require xml)
 9(xexpr->string doc)           ; xexpr -> XML string
10(string->xexpr "<xml>...</xml>")  ; XML string -> xexpr
11
12; Reading XML files
13(define xexpr
14  (string->xexpr
15    (if (bytes? param)
16        (bytes->string/utf-8 param)
17        param)))

Building XML Dynamically

1(define (make-xml-body #:title title #:content content)
2  `(document
3     (metadata
4       (title ,title)
5       (timestamp ,(current-time-string)))
6     (body
7       (section ,content))))

Making HTTP Requests

 1(require net/http-easy)
 2
 3; POST request with headers
 4(define response
 5  (post url
 6    #:headers (hash 'content-type "application/json")
 7    #:data request-body))
 8
 9(define body (bytes->string/utf-8 (response-body response)))
10(define status (response-status-code response))

URL Operations

1(require net/url)
2
3(define url-struct (string->url "https://api.example.com/v1"))
4(url-host url-struct)          ; Extract host
5(url-path url-struct)          ; Extract path

Formatting Time and Dates (HTTP & ISO 8601)

Current Time Formatting

 1(require srfi/19)
 2
 3; RFC 7231 HTTP date format
 4(define (http-date-string)
 5  (define date (time-utc->date (make-time 'time-utc 0 (current-seconds))))
 6  (date->string date "~a, ~d ~b ~Y ~H:~M:~S GMT"))
 7; => "Thu, 02 Oct 2025 14:30:45 GMT"
 8
 9; ISO 8601 date
10(date->string date "~Y-~m-~d")
11; => "2025-10-02"

Gotcha: Default parameter values are evaluated at call time:

1; CORRECT - fresh timestamp each call
2(define (timestamp [secs (current-seconds)])
3  (format-time secs))
4
5; WRONG - timestamp frozen at definition time in some contexts

Managing Configuration with Environment Variables

Reading Config

 1; Simple read
 2(getenv "API_KEY")  ; => string or #f
 3
 4; With default value
 5(define (get-config key [default #f])
 6  (or (getenv key) default))
 7
 8; With error on missing
 9(define (require-config key)
10  (or (getenv key)
11      (error 'config "Missing required env var: ~a" key)))

Environment-Based Behavior

1(define app-env (or (getenv "APP_ENV") "prod"))
2
3(define debug? (string=? "dev" app-env))
4(define prod?  (string=? "prod" app-env))
5
6(when debug?
7  (displayln "Debug mode enabled"))

File I/O: Reading, Writing, and Paths

Reading Files

 1(require racket/file)
 2
 3; Read entire file
 4(file->string "/path/to/file.txt")
 5(file->bytes "/path/to/file.bin")
 6
 7; Write file
 8(write-to-file data path
 9  #:mode 'text          ; or 'binary
10  #:exists 'replace)    ; or 'append, 'error, 'truncate

Path Operations

1(require racket/path)
2
3; Build paths safely
4(build-path "dir" "subdir" "file.txt")
5
6; System paths
7(find-system-path 'orig-dir)    ; Original working directory
8(find-system-path 'temp-dir)    ; Temp directory

Critical Gotcha: raco test changes the working directory:

1; WRONG - breaks in tests
2(define key-path "certs/key.pem")
3
4; CORRECT - use absolute paths
5(define key-path
6  (build-path (find-system-path 'orig-dir) "certs" "key.pem"))

Building a Command-Line Interface (CLI)

Argument Parsing

 1(define file-param (make-parameter #f))
 2(define id-param (make-parameter #f))
 3
 4(define cli
 5  (command-line
 6    #:program "app-name"
 7    #:once-each
 8    [("-f" "--file") path "Input file path"
 9                     (file-param path)]
10    [("-i" "--id") id "Record ID"
11                   (id-param id)]
12    #:args (command)
13    command))
14
15; Use with match
16(match cli
17  ["process" (process-file (file-param))]
18  ["help" (display-help)]
19  [_ (error "Unknown command")])

Unit Testing with Rackunit

Basic Test Structure

1(module+ test
2  (require rackunit)
3
4  (test-case "description"
5    (check-equal? actual expected)
6    (check-true (predicate? value))
7    (check-exn exn:fail? (lambda () (failing-operation)))))

Test Suites

1(define my-tests
2  (test-suite
3    "Feature tests"
4    (test-case "case 1" ...)
5    (test-case "case 2" ...)))
6
7(run-tests my-tests)

Exception Testing

1; Test that function raises exception
2(check-exn exn:fail?
3  (lambda () (function-that-should-fail)))
4
5; Test specific error message
6(check-exn #rx"specific error"
7  (lambda () (failing-function)))

Common Pitfalls and How to Avoid Them

1. Multiple Return Values

1; WRONG - only captures first value
2(define response (http-request url))
3
4; CORRECT - captures all values
5(define-values (body status) (http-request url))

2. Bytes vs Strings

HTTP libraries often return bytes, XML functions expect strings:

1; Common pattern
2(define xml-data
3  (string->xexpr
4    (if (bytes? param)
5        (bytes->string/utf-8 param)
6        param)))

3. Parameter Default Values

1; Default evaluated at call time (good for timestamps)
2(define (log-message msg [time (current-seconds)])
3  ...)
4
5; Each call gets fresh timestamp

4. Working Directory in Tests

Tests run in different directory:

1; ALWAYS use absolute paths for file operations
2(define config-path
3  (build-path (find-system-path 'orig-dir) "config.json"))

Performance Optimization Techniques

1. Immutable vs Mutable

Prefer immutable data structures - they’re optimized:

1(make-immutable-hash alist)    ; Preferred
2(make-hash alist)              ; Only if mutation needed

2. List Comprehensions

Use for/list, for/hash for efficient collection building:

1; Build list
2(for/list ([item items])
3  (process item))
4
5; Build hash
6(for/hash ([pair pairs])
7  (values (car pair) (cdr pair)))

3. String Building

Use string-join instead of repeated string-append:

1; SLOW
2(foldl string-append "" string-list)
3
4; FAST
5(string-join string-list "")

Summary of Idiomatic Racket Best Practices

  1. Always use contracts for exported functions
  2. Test submodules for all library code
  3. Absolute paths for file operations
  4. define-values for multi-return functions
  5. Immutable data by default
  6. X-expressions for XML processing
  7. Parameters for CLI arguments
  8. Pattern matching over conditionals
Tags: Racket, Functional-Programming, Lisp, Scheme, Programming-Language