DEV Community

Cover image for The Comprehensive Racket & Functional Programming Cheat Sheet
Michael Otu
Michael Otu

Posted on

The Comprehensive Racket & Functional Programming Cheat Sheet

Over the weekend, I took a detour into the lisp land and I met racket. This is what I was able to piece together


Phase 1: Syntax & Core Arithmetic

Racket uses prefix notation enclosed in execution parentheses (operator arg1 arg2). The open parenthesis ( acts as an execution trigger. Evaluation runs from the innermost to the outermost parentheses.

Core Examples

;; Basic Arithmetic
(+ 10 5 2) ;; Returns 17
(* 10 5 2) ;; Returns 100

;; Nested Expressions (No PEMDAS needed)
(_ (+ 4 6) (- 12 7)) ;; Evaluates 10 _ 5 -> Returns 50
Enter fullscreen mode Exit fullscreen mode

Parentheses Golden Rule

Only use a parenthesis when invoking a command, operator, or function.

  • (+ 5 (10)) CRASHES (tries to run the number 10 as a function).
  • ((+ 5 5)) CRASHES (evaluates to 10, then tries to run the number 10).

Phase 2: Core Data Structures & Variables

Global bindings are created using define. Values are immutable and cannot be changed over time.

The Four Atomic Data Types

  1. Numbers: Integers (45), decimals (3.14), or fractions (1/3).
  2. Strings: Text wrapped in double quotes ("Hello").
  3. Booleans: True (#t) and False (#f).
  4. Symbols: Lightweight, immutable identifier tokens prefixed with a single quote ('success).

Core Examples

(define radius 5)
(define pi 3.14)
(define status 'success)
Enter fullscreen mode Exit fullscreen mode

Phase 3: Conditionals & Logic

Conditional operations are expressions that evaluate down to a single return value.

Core Operators & Flow Control

  • and / or / not: Standard logical short-circuiting prefix operators.
  • if: Takes exactly three arguments: (if condition true-branch false-branch). No else keyword.
  • cond: Evaluates multiple branches sequentially. Uses/can use [...] for human readability.

Core Examples

(and (> 15 10) (< 15 20)) ;; Returns #t

(if (> temperature 30) 'hot 'cold)

(cond
[(>= score 90) 'A]
[(>= score 80) 'B]
[else 'F])
Enter fullscreen mode Exit fullscreen mode

Phase 4: Functions & Scope

Functions automatically return the value of their body expression without an explicit return keyword.

Named, Anonymous, & Scoped Blocks

  • Named Functions: Defined by grouping the name and parameters in parentheses: (define (name args) body).
  • Anonymous Functions (lambda): Throwaway functions built on the fly: (lambda (args) body).
  • let (Parallel): Creates local variables simultaneously. Variables cannot see each other during setup.
  • let\* (Sequential): Creates local variables one after the other. Later variables can reference earlier ones.

Core Examples

;; Named Function
(define (double n) (\* n 2))

;; Inline Lambda Execution
((lambda (n) (\* n 2)) 10) ;; Returns 20

;; Sequential Local Bindings
(let* ([x 10]
[y (* x 5)])
(+ x y)) ;; Returns 60
Enter fullscreen mode Exit fullscreen mode

Phase 5: Lists & Modern List Operations

Lists are ordered sequential collections. They are processed using either historical Lisp conventions or modern aliases.

Creation & Extraction

  • list: Evaluates arguments into a sequential list.
  • '(): Represents the literal base empty list.
  • cons: Prepends a single element onto the front of an existing list.
  • First Item: Extracted via car (traditional) or first (modern).
  • Remaining List: Extracted via cdr (traditional) or rest (modern).

Core Examples

(define my-list (list 100 #t 'hello)) ;; Creates '(100 #t hello)
(cons 'apples '(bananas cherries)) ;; Returns '(apples bananas cherries)

(car (cdr '(apples bananas cherries))) ;; Returns 'bananas
(first (rest '(apples bananas cherries))) ;; Returns 'bananas

(if (empty? my-list) "Closed" (length my-list)) ;; Returns 3
Enter fullscreen mode Exit fullscreen mode

Phase 6: Iteration & Higher-Order Functions

Instead of using loops that alter data in place, functional programming relies on Higher-Order Functions to process immutable collections.

The Big Four

  • map: Loops over a list, passes each item through a transformation function, and returns a new list.
  • filter: Loops over a list, keeps items that evaluate to #t against a predicate condition, and drops the rest.
  • foldl (Fold-Left): Reduces a list down to a single value by processing elements from left to right (front to back).
  • foldr (Fold-Right): Reduces a list down to a single value by processing elements from right to left (back to front). Preserves list structures when rebuilding with cons.

Core Examples

(map (lambda (x) (* x 2)) '(5 10 15 20)) ;; Returns '(10 20 30 40)
(filter (lambda (n) (= n 5)) '(2 5 7 5 9 1)) ;; Returns '(5 5)

(foldl
  (lambda (n total) (_ n total))
  1
  '(2 3 4)) ;; 4 _ (3 _ (2 _ 1)) -> Returns 24

(foldr
  -
  0
  '(5 3)) ;; 5 - (3 - 0) -> Returns 2
Enter fullscreen mode Exit fullscreen mode

Phase 7: Recursion & Tail Call Optimization (TCO)

Recursion replaces traditional loops. A proper recursive function requires a Base Case (the exit clause) and a Recursive Step (the self-call with a smaller argument).

Memory Optimization Rules

  • Standard Recursion: Traps the recursive call inside another function (like + or append), forcing the call stack memory to expand linearly (O(N) space).
  • Tail Call Optimization (TCO): If the recursive call sits in the tail position (the absolute final expression evaluated), Racket reuses the same memory frame, running in constant (O(1)) space.
  • Accumulator Pattern: Passing a running total down as an argument is the primary strategy used to shift standard recursion into tail position optimization.

Core Examples

;; ❌ Standard Recursion (No TCO - Memory Expands)
(define (sum-list lst)
  (if (empty? lst)
    0
    (+ (first lst) (sum-list (rest lst)))))

;; Tail Recursion (TCO Active - Memory Stays Flat)
(define (sum-list-tco lst)
  (define (helper remaining accumulator)
    (if (empty? remaining)
      accumulator
      (helper
        (rest remaining)
        (+ (first remaining) accumulator))))
    (helper lst 0))
Enter fullscreen mode Exit fullscreen mode

Phase 8: Advanced Ecosystem Engineering

1. Hash Maps & Unique Sets

  • #hash: Stores key-value pairings. Keywords passed to lookup tools like hash-ref must be quoted ('#:key) to prevent compiler namespace collisions. If using standard symbols inside #hash, omit inner quotes.
  • set: Collections guaranteeing element uniqueness. Tested via set-member? and extended via set-add.
(define user #hash((#:name . "Alice")))
(hash-ref user '#:name) ;; Returns "Alice"

(define book #hash((title . "Dune")))
(hash-ref book 'title) ;; Returns "Dune"

(set-member? (set 1 2 2 3) 2) ;; Returns #t
Enter fullscreen mode Exit fullscreen mode

2. State & Mutability (box)

  • box: Creates a reference wrapper around mutable data. Read via unbox and mutated via set-box!. Functions with an exclamation mark ! signal structural mutation.
  • begin: Chains sequential side-effect operations from top to bottom, returning only the evaluation of the final expression.
(define health (box 100))
(define (take-damage!)
(begin
(set-box! health (- (unbox health) 10))
(unbox health)))
Enter fullscreen mode Exit fullscreen mode

3. Type Checking & Casting

  • Predicates (?): Validate runtime types (e.g., string?, number?, symbol?).
  • Casting (->): Converts data formats. string->number safely returns #f if given invalid textual input.
(if (string? "50")
  (* (string->number "50")
  2) 'error) ;; Returns 100
Enter fullscreen mode Exit fullscreen mode

4. Modules & Namespaces

  • provide: Declares which parts of a filesystem file are exported publicly.
  • require: Ingests public features from an external sandbox by loading its relative string filepath.
;; Inside file-a.rkt
(provide double)
(define (double x) (* x 2))

;; Inside main.rkt
(require "file-a.rkt")
(double 10) ;; Returns 20
Enter fullscreen mode Exit fullscreen mode

5. Macros (define-syntax-rule)

  • Macros process raw, unevaluated source code at compile-time to inject new keywords.
  • Racket macros are hygienic, meaning the compiler automatically isolates macro identifiers so they never accidentally overwrite or conflict with user variables.
(define-syntax-rule (swap! box1 box2)
  (let ([temp (unbox box1)])
    (begin
      (set-box! box1 (unbox box2))
      (set-box! box2 temp))))
Enter fullscreen mode Exit fullscreen mode

Top comments (0)