···11+---
22+name: racket
33+description: "Use this skill whenever writing, reading, editing, reviewing, or debugging Racket code (.rkt files). Triggers include: any mention of 'Racket', '#lang racket', '.rkt', 'raco', 'syntax-parse', 'DrRacket', or requests involving s-expression-based Lisp/Scheme dialects in a Racket context. Also use when working with Racket macros, Racket package management, Typed Racket, Scribble documentation, or any Racket-ecosystem tool (rackunit, rebellion, resyntax, etc). Use this skill even for tasks that look like 'generic Lisp' if the user's project context is Racket. Do NOT use for Common Lisp, Clojure, Emacs Lisp, or Scheme implementations other than Racket."
44+---
55+66+# Racket Programming
77+88+## Overview
99+1010+Racket is a language-oriented programming language descended from Scheme. It is NOT simply "another Scheme" — Racket has its own idioms, standard library, macro system, module system, and conventions that differ significantly from R5RS/R6RS/R7RS Scheme and from Common Lisp. Code that looks like "generic Scheme" is usually not idiomatic Racket. Racket developers often call themselves "Racketeers" (in the Scheme tradition of naming things after illicit activities).
1111+1212+This skill covers idiomatic Racket style, common pitfalls that AI coding agents make, project structure, testing, macros, and documentation.
1313+1414+**Reference**: The official Racket style guide is at https://docs.racket-lang.org/style/index.html — consult it when uncertain.
1515+1616+---
1717+1818+## Critical: Things AI Agents Get Wrong
1919+2020+These are the most common mistakes. Internalize these before writing any Racket code.
2121+2222+### 1. Do NOT write Scheme — write Racket
2323+2424+```racket
2525+;; WRONG — this is Scheme, not Racket
2626+(define (map-filter f pred lst)
2727+ (cond
2828+ [(null? lst) '()]
2929+ [(pred (car lst))
3030+ (cons (f (car lst)) (map-filter f pred (cdr lst)))]
3131+ [else (map-filter f pred (cdr lst))]))
3232+3333+;; RIGHT — idiomatic Racket uses for loops, match, and the standard library
3434+(define (map-filter f pred lst)
3535+ (for/list ([x (in-list lst)]
3636+ #:when (pred x))
3737+ (f x)))
3838+```
3939+4040+Key differences from Scheme:
4141+- Use `#lang racket` (not `#lang scheme` or `#lang r5rs`)
4242+- Use square brackets `[]` for cond clauses, let bindings, and for clauses
4343+- Use `for/list`, `for/fold`, `for/hash`, etc. instead of manual recursion over lists
4444+- Use `match` and `match-define` for destructuring, not `car`/`cdr` chains
4545+- Use `first`, `rest`, `empty?` over `car`, `cdr`, `null?` (though the latter work)
4646+- Use `string-append`, `string-join`, etc. — not `display` with `string-port`
4747+- Use `hash` tables, not association lists, for key-value data
4848+- Use `struct` (not `define-record-type` or manual constructors)
4949+- Use `define/contract` or `->` contracts, not ad-hoc assertions
5050+5151+### 2. Square brackets are conventional, not optional
5252+5353+Racket uses `[]` by convention in specific positions. This is one of the most visible markers of idiomatic vs non-idiomatic code.
5454+5555+```racket
5656+;; WRONG — all parens
5757+(cond
5858+ ((empty? lst) 0)
5959+ ((> (first lst) 10) (add1 (count-big (rest lst))))
6060+ (else (count-big (rest lst))))
6161+6262+;; RIGHT — square brackets for cond clauses
6363+(cond
6464+ [(empty? lst) 0]
6565+ [(> (first lst) 10) (add1 (count-big (rest lst)))]
6666+ [else (count-big (rest lst))])
6767+```
6868+6969+Use `[]` in these positions:
7070+- `cond` clauses: `[test expr ...]`
7171+- `match` clauses: `[(pattern) expr ...]`
7272+- `let`/`let*`/`letrec` bindings: `(let ([x 1] [y 2]) ...)`
7373+- `for` clauses: `(for/list ([x (in-list xs)]) ...)`
7474+- `case` clauses: `[(datum ...) expr ...]`
7575+- `with-handlers` clauses: `([exn:fail? handler])`
7676+- `syntax-parse` clauses and attribute bindings
7777+- `parameterize` bindings: `(parameterize ([param val]) ...)`
7878+7979+Do NOT use `[]` for:
8080+- Function application: use `(f x)` not `[f x]`
8181+- Function definitions: use `(define (f x) ...)` not `(define [f x] ...)`
8282+- The outermost form of any expression
8383+8484+### 3. Prefer `define` over `let` — reduce indentation
8585+8686+```racket
8787+;; WRONG — unnecessary nesting
8888+(define (process data)
8989+ (let* ([cleaned (clean data)]
9090+ [parsed (parse cleaned)]
9191+ [result (analyze parsed)])
9292+ (format-output result)))
9393+9494+;; RIGHT — flat defines in a body context
9595+(define (process data)
9696+ (define cleaned (clean data))
9797+ (define parsed (parse cleaned))
9898+ (define result (analyze parsed))
9999+ (format-output result))
100100+```
101101+102102+This is the Racket style guide's explicit recommendation. `let*` is appropriate when you need sequential scope explicitly, but a series of `define` forms in a function body is preferred for readability.
103103+104104+**Warning**: `define` in a body context has mutually recursive scope (like `letrec`), not sequential scope (like `let*`). This matters if bindings reference each other. In practice, this rarely causes issues for value bindings but is important for function bindings.
105105+106106+### 4. Use `for` loops, not `map`/`filter` with lambda
107107+108108+```racket
109109+;; OK but not preferred
110110+(map (lambda (x) (* x x)) (filter even? lst))
111111+112112+;; BETTER — for loop is more readable and general
113113+(for/list ([x (in-list lst)]
114114+ #:when (even? x))
115115+ (* x x))
116116+```
117117+118118+The `for` family of loops (`for/list`, `for/fold`, `for/hash`, `for/sum`, `for/and`, `for/or`, `for/first`, `for/vector`, etc.) is the idiomatic way to iterate in Racket. They:
119119+- Avoid intermediate lambdas
120120+- Generalize across sequence types (lists, vectors, hashes, ranges, etc.)
121121+- Support `#:when`, `#:unless`, `#:break`, `#:final` clauses
122122+- Can iterate over multiple sequences in parallel
123123+124124+**Important**: Always use `in-list`, `in-vector`, `in-hash`, `in-range`, etc. in `for` clauses for both clarity and performance. These are macros created with `define-sequence-syntax` and are recognized specially by `for` at compile time, enabling optimized iteration. A bare list variable in a `for` clause works but falls back to the generic (slower) sequence protocol.
125125+126126+Note that `for` loops (but NOT `for*` loops) iterate multiple sequence clauses in lockstep. This is useful for pairing a sequence with its indices:
127127+128128+```racket
129129+;; Find the index of the first comma in a string starting from pos
130130+(for/first ([c (in-string line pos)]
131131+ [i (in-naturals pos)]
132132+ #:when (char=? c #\,))
133133+ i)
134134+```
135135+136136+Do NOT use `for/or` with `(and condition value)` as a workaround for this — use `for/first` with a second lockstep clause instead.
137137+138138+```racket
139139+;; WRONG — bare list, slower and less clear
140140+(for/list ([x xs]) (add1 x))
141141+142142+;; RIGHT — explicit sequence constructor
143143+(for/list ([x (in-list xs)]) (add1 x))
144144+```
145145+146146+### 5. Use `match` for destructuring
147147+148148+```racket
149149+;; WRONG — positional accessors
150150+(define (point-distance p)
151151+ (sqrt (+ (sqr (point-x p)) (sqr (point-y p)))))
152152+153153+;; RIGHT — match-define for clean destructuring
154154+(define (point-distance p)
155155+ (match-define (point x y) p)
156156+ (sqrt (+ (sqr x) (sqr y))))
157157+158158+;; ALSO RIGHT — match in function position
159159+(define (describe-result result)
160160+ (match result
161161+ [(success value) (format "OK: ~a" value)]
162162+ [(failure msg) (format "Error: ~a" msg)]))
163163+```
164164+165165+### 6. Closing parentheses go on the SAME line
166166+167167+```racket
168168+;; WRONG — C/Java style brace placement
169169+(define (factorial n)
170170+ (if (zero? n)
171171+ 1
172172+ (* n (factorial (sub1 n)))
173173+ )
174174+)
175175+176176+;; RIGHT — closing parens on the last line of the expression
177177+(define (factorial n)
178178+ (if (zero? n)
179179+ 1
180180+ (* n (factorial (sub1 n)))))
181181+```
182182+183183+This is non-negotiable in Racket. Never put closing parentheses on their own line.
184184+185185+### 7. Comments follow Lisp/Racket conventions
186186+187187+```racket
188188+;;;; File-level header (rare)
189189+190190+;;; Section header
191191+192192+;; Normal comment explaining the next form or block
193193+(define (foo x)
194194+ (+ x 1)) ; inline comment for a specific expression
195195+```
196196+197197+- `;` — inline comments (end of line)
198198+- `;;` — line comments (start of line, most common)
199199+- `;;;` — section headers
200200+- `;;;;` — file headers (rare)
201201+- `#;` — comment out one s-expression (very useful for debugging)
202202+- `#| ... |#` — block comments (rare, for commenting out large blocks)
203203+204204+### 8. Naming conventions
205205+206206+- Use `kebab-case` (hyphenated): `my-function`, `parse-input`, `default-timeout`
207207+- Do NOT use `snake_case` or `camelCase`
208208+- Predicates end with `?`: `empty?`, `string?`, `valid-input?`
209209+- Mutating procedures end with `!`: `set!`, `vector-set!`, `hash-set!`
210210+- Conversion functions use `->`: `string->number`, `list->vector`
211211+- Type/struct names are nouns: `point`, `employee`, `syntax-token`
212212+- Do NOT use `_` (underscore) in names — it's reserved for "don't care" patterns in `match` and `syntax-parse`
213213+- Avoid plural collection names: prefer `racket/list` not `racket/lists`
214214+215215+---
216216+217217+## Project Structure
218218+219219+### Single-collection package (most common)
220220+221221+```
222222+my-package/
223223+├── info.rkt ; Package metadata
224224+├── main.rkt ; Primary module (require'd as just "my-package")
225225+├── private/ ; Internal modules not intended for external use
226226+│ ├── helper.rkt
227227+│ └── util.rkt
228228+├── scribblings/ ; Documentation
229229+│ └── my-package.scrbl
230230+└── test/ ; Tests (or use module+ test inline)
231231+ └── test-main.rkt
232232+```
233233+234234+### info.rkt for a single-collection package
235235+236236+```racket
237237+#lang info
238238+239239+(define collection "my-package")
240240+(define version "0.1")
241241+(define deps '("base"))
242242+(define build-deps '("rackunit-lib" "scribble-lib" "racket-doc"))
243243+(define scribblings '(("scribblings/my-package.scrbl")))
244244+(define pkg-desc "Short description of the package")
245245+(define license 'Apache-2.0)
246246+```
247247+248248+### Multi-collection package
249249+250250+```
251251+my-package/
252252+├── info.rkt ; (define collection 'multi)
253253+├── my-lib/
254254+│ ├── info.rkt ; Collection-level info
255255+│ ├── main.rkt
256256+│ └── private/
257257+├── my-lib-test/
258258+│ ├── info.rkt
259259+│ └── tests.rkt
260260+└── my-lib-doc/
261261+ ├── info.rkt
262262+ └── scribblings/
263263+```
264264+265265+### Key commands
266266+267267+- `raco pkg install` — install a package (from current directory or source)
268268+- `raco pkg install --link` — link a local development directory as a package
269269+- `raco setup` — recompile and rebuild *all* installed Racket code. This is the most common workflow during development — no need to track which specific collections changed.
270270+- `raco setup <collection>` — recompile and rebuild only a specific collection
271271+- `raco test <file-or-directory>` — run tests
272272+- `raco test --drdr <file-or-directory>` — run tests in DrDr mode, which parallelizes test execution and is slightly stricter. This is the default mode used by the Racket package catalog build server, so test with this flag before publishing.
273273+- `raco test -p <package>` — run all tests in a package
274274+- `raco docs` — view local documentation
275275+- `raco pkg new <name>` — generate a new package skeleton
276276+277277+---
278278+279279+## Testing
280280+281281+### Inline tests with module+ test (preferred)
282282+283283+```racket
284284+#lang racket
285285+286286+(provide double)
287287+288288+(define (double x)
289289+ (* x 2))
290290+291291+(module+ test
292292+ (require rackunit)
293293+ (check-equal? (double 5) 10)
294294+ (check-equal? (double 0) 0)
295295+ (check-equal? (double -3) -6))
296296+```
297297+298298+The `module+ test` submodule is the idiomatic way to write tests in Racket. Tests live alongside the code they test but only run when explicitly invoked via `raco test`.
299299+300300+Multiple `module+ test` blocks in the same file are combined into a single test submodule — you can place test blocks near the functions they test. This is a good way to keep files easy to scan. Place the `(module+ test (require rackunit))` part in its own block near the top of the file, alongside the other `require` statements:
301301+302302+```racket
303303+#lang racket/base
304304+305305+(require racket/list)
306306+307307+(provide my-function)
308308+309309+(module+ test
310310+ (require rackunit))
311311+312312+(define (my-function x)
313313+ (* x 2))
314314+315315+(module+ test
316316+ (test-case "my-function"
317317+ (test-case "doubles positive numbers"
318318+ (check-equal? (my-function 5) 10))
319319+ (test-case "handles zero"
320320+ (check-equal? (my-function 0) 0))))
321321+322322+(define (helper y)
323323+ (+ y 1))
324324+325325+(module+ test
326326+ (test-case "helper"
327327+ (test-case "increments by one"
328328+ (check-equal? (helper 5) 6))))
329329+```
330330+331331+Group all test cases for a function under a single `test-case` named after the function. Test cases can be nested in a tree structure, and their names affect the output of testing tools.
332332+333333+### rackunit essentials
334334+335335+```racket
336336+(require rackunit)
337337+338338+;; Basic checks
339339+(check-equal? actual expected) ; equality
340340+(check-not-equal? actual expected) ; inequality
341341+(check-true expr) ; must be #t
342342+(check-false expr) ; must be #f
343343+(check-pred predicate value) ; (predicate value) must be true
344344+(check-exn exn:fail? thunk) ; thunk must raise the given exception
345345+(check-not-exn thunk) ; thunk must not raise
346346+347347+;; Test cases for grouping (preferred)
348348+(test-case "descriptive name"
349349+ (check-equal? (foo 1) 2)
350350+ (check-equal? (foo 2) 4))
351351+```
352352+353353+**Avoid `test-suite`.** Test suites predate the submodule system and are rarely useful in modern Racket. They add complexity without much benefit — just use `test-case` for grouping and `module+ test` for structure.
354354+355355+### Separate test files
356356+357357+For larger test suites, create a `test/` directory. **Always put tests in `module+ test` submodules**, even in files within a `test/` directory. This eliminates all ambiguity about what is test code vs. non-test code, and ensures tools (like `raco test`, `raco cover`, code stripping for binary packages) treat test code uniformly regardless of where it lives in the file system.
358358+359359+---
360360+361361+## Macros
362362+363363+Racket has a powerful, hygienic macro system. There is a hierarchy of macro-definition forms:
364364+365365+### When to use macros vs functions
366366+367367+**Use functions when possible.** The Racket style guide is explicit: do not introduce macros when functions will do. Functions compose better, are usable in higher-order contexts, and are simpler to understand.
368368+369369+Use macros when you need to:
370370+- Control evaluation order (short-circuiting, delayed evaluation)
371371+- Introduce new binding forms
372372+- Transform syntax (new language constructs)
373373+- Generate compile-time errors for invalid usage
374374+- Work at the level of syntax rather than values
375375+376376+### Macro definition forms
377377+378378+**Always use the `syntax-parse` macro system.** The `syntax-rules` and `syntax-case` systems are functionally obsolete in modern Racket. They lack `syntax-parse`'s automatic error reporting, syntax classes, and pattern directives.
379379+380380+1. **`define-syntax-parse-rule`** — simplest, for pattern-only macros (one clause)
381381+382382+```racket
383383+(require (for-syntax racket/base syntax/parse))
384384+385385+(define-syntax-parse-rule (swap! a:id b:id)
386386+ (let ([tmp a])
387387+ (set! a b)
388388+ (set! b tmp)))
389389+```
390390+391391+Note: `define-syntax-parse-rule` is the modern name for `define-simple-macro`. Use the former.
392392+393393+2. **`define-syntax` + `syntax-parse`** — full power, for anything with multiple clauses, side conditions, or complex logic
394394+395395+```racket
396396+(require (for-syntax racket/base syntax/parse))
397397+398398+(define-syntax (my-cond stx)
399399+ (syntax-parse stx
400400+ [(_ [test:expr body:expr ...+] ...+)
401401+ #'(cond [test body ...] ...)]))
402402+```
403403+404404+Do NOT use `define-syntax-rule` for anything nontrivial — it provides no syntax class annotations and produces poor error messages. Prefer `define-syntax-parse-rule` even for simple cases.
405405+406406+### syntax-parse best practices
407407+408408+`syntax-parse` is the modern, recommended way to write macros in Racket. It provides:
409409+- Syntax classes for reusable pattern components
410410+- Automatic error reporting with good messages
411411+- Pattern directives (`#:when`, `#:with`, `#:fail-when`, etc.)
412412+- Backtracking across clauses
413413+414414+```racket
415415+;; Define reusable syntax classes
416416+(begin-for-syntax
417417+ (define-syntax-class binding-pair
418418+ #:description "binding pair"
419419+ (pattern [name:id value:expr])))
420420+421421+(define-syntax (my-let stx)
422422+ (syntax-parse stx
423423+ [(_ (b:binding-pair ...) body:expr ...+)
424424+ #'(let ([b.name b.value] ...) body ...)]))
425425+```
426426+427427+Key points:
428428+- Always `(require (for-syntax racket/base syntax/parse))` — these are not automatically available
429429+- Use `:expr`, `:id`, `:keyword`, `:str`, `:nat`, etc. for built-in syntax classes
430430+- Use `...` (ellipsis) for repetition, `...+` for one-or-more
431431+- Use `#:literals` to match specific identifiers
432432+- Use `~and`, `~or`, `~seq`, `~optional` for complex patterns
433433+- Use `#'template` (shorthand for `(syntax template)`) to produce output
434434+435435+### Phase levels
436436+437437+Racket has a strict phase separation system. Code that runs at compile time (phase 1) must be explicitly required at that phase.
438438+439439+```racket
440440+(require (for-syntax racket/base)) ; phase 1 (compile time)
441441+(require (for-template racket/base)) ; phase -1 (used in code generation)
442442+(require (for-meta 2 racket/base)) ; phase 2 (macros that define macros)
443443+```
444444+445445+Common phase-level mistakes:
446446+- Forgetting `(require (for-syntax racket/base))` when writing macros
447447+- Trying to use a runtime binding at compile time
448448+- Forgetting that `begin-for-syntax` runs at phase 1
449449+450450+---
451451+452452+## Module System
453453+454454+### require and provide
455455+456456+```racket
457457+#lang racket
458458+459459+;; Provide specific bindings
460460+(provide function-a
461461+ function-b
462462+ struct-name)
463463+464464+;; Provide everything
465465+(provide (all-defined-out))
466466+467467+;; Provide with contracts
468468+(provide
469469+ (contract-out
470470+ [function-a (-> string? number?)]
471471+ [struct-name ([field-a string?] [field-b number?])]))
472472+473473+;; Require from collections
474474+(require racket/list ; specific collection module
475475+ racket/match ; usually already in #lang racket
476476+ "private/helper.rkt" ; relative path
477477+ (only-in racket/string string-join string-split)
478478+ (prefix-in http: net/http-easy))
479479+```
480480+481481+### #lang line
482482+483483+Every Racket source file starts with `#lang`:
484484+485485+```racket
486486+#lang racket ; full Racket language
487487+#lang racket/base ; minimal Racket (faster to load, explicit requires)
488488+#lang typed/racket ; Typed Racket
489489+#lang scribble/manual ; documentation
490490+#lang info ; package metadata (info.rkt files)
491491+```
492492+493493+Use `#lang racket/base` for library code when you want faster startup and explicit dependencies. Use `#lang racket` for scripts and applications where convenience matters more.
494494+495495+---
496496+497497+## Common Patterns and Standard Library
498498+499499+### Hash tables
500500+501501+```racket
502502+;; Immutable hashes (preferred)
503503+(define h (hash "a" 1 "b" 2 "c" 3))
504504+(hash-ref h "a") ; => 1
505505+(hash-set h "d" 4) ; => new hash with "d" added
506506+(hash-update h "a" add1) ; => new hash with "a" incremented
507507+508508+;; Iterating
509509+(for ([(k v) (in-hash h)])
510510+ (printf "~a: ~a\n" k v))
511511+512512+;; Building from iteration
513513+(for/hash ([x (in-list items)])
514514+ (values (item-key x) (item-value x)))
515515+```
516516+517517+### Structs
518518+519519+```racket
520520+;; Basic struct
521521+(struct point (x y) #:transparent)
522522+523523+;; With contracts and methods
524524+(struct employee (name salary department)
525525+ #:transparent
526526+ #:methods gen:custom-write
527527+ [(define (write-proc emp port mode)
528528+ (fprintf port "<employee:~a>" (employee-name emp)))])
529529+```
530530+531531+`#:transparent` makes structs printable and comparable — use it unless you have a reason not to.
532532+533533+### String operations
534534+535535+```racket
536536+(require racket/string)
537537+538538+(string-join '("a" "b" "c") ", ") ; => "a, b, c"
539539+(string-split "a,b,c" ",") ; => '("a" "b" "c")
540540+(string-contains? "hello world" "world") ; => #t
541541+(string-prefix? "hello" "hel") ; => #t
542542+(string-trim " hello ") ; => "hello"
543543+(~a 42) ; => "42" (any value to string)
544544+(~v '(1 2 3)) ; => "'(1 2 3)" (verbose/print-style)
545545+```
546546+547547+### Formatting output
548548+549549+```racket
550550+;; format returns a string
551551+(format "Name: ~a, Age: ~a" name age)
552552+553553+;; printf prints directly
554554+(printf "Processing ~a of ~a\n" current total)
555555+556556+;; ~a = display style (human-readable)
557557+;; ~v = print style (Racket-readable, like ~s but modern)
558558+;; ~s = write style (legacy Racket-readable)
559559+;; ~e = error-message style (rarely useful; see fprintf docs)
560560+```
561561+562562+### Error handling
563563+564564+```racket
565565+;; Raising errors — prefer raise-argument-error, raise-arguments-error, etc.
566566+;; These produce messages conforming to Racket's Error Message Conventions.
567567+;; See: https://docs.racket-lang.org/reference/exns.html#%28part._err-msg-conventions%29
568568+(raise-argument-error 'function-name "positive integer" arg)
569569+(raise-arguments-error 'function-name
570570+ "index out of range"
571571+ "index" idx
572572+ "valid range" (format "[0, ~a)" len))
573573+574574+;; Avoid `error` — it is lightly discouraged in modern Racket because its
575575+;; format-string style doesn't conform to Racket's error message conventions.
576576+;; Use raise-argument-error, raise-arguments-error, or raise-result-error instead.
577577+;; (error 'fn "expected ~a, got ~a" expected actual) ; avoid this
578578+579579+;; Handling errors
580580+(with-handlers ([exn:fail:filesystem? (lambda (e) (default-value))]
581581+ [exn:fail:network? (lambda (e) (retry))])
582582+ (do-risky-operation))
583583+```
584584+585585+### Working with paths and files
586586+587587+```racket
588588+(require racket/path)
589589+590590+(define p (build-path "src" "main.rkt"))
591591+(path->string p)
592592+(file-exists? p)
593593+(directory-list "src")
594594+(make-directory* "path/to/new/dir") ; like mkdir -p
595595+596596+;; Reading/writing files
597597+(file->string "data.txt")
598598+(file->lines "data.txt")
599599+(display-to-file content "output.txt" #:exists 'replace)
600600+601601+;; Port-based I/O
602602+(call-with-input-file "data.txt"
603603+ (lambda (in)
604604+ (for/list ([line (in-lines in)])
605605+ (process-line line))))
606606+```
607607+608608+---
609609+610610+## Formatting Rules
611611+612612+- Maximum line width: 102 characters (per Racket style guide). Prefer 80 if feasible.
613613+- Do NOT use tab characters. Use spaces only.
614614+- Indent subexpressions by 2 spaces when they are body forms.
615615+- Align arguments vertically when they overflow a line.
616616+- All closing parentheses go on the same line as the last expression.
617617+- Put a blank line between top-level definitions.
618618+- Put the `#lang` line first, then `require`s, then `provide`s, then definitions.
619619+620620+```racket
621621+#lang racket
622622+623623+(require racket/string
624624+ racket/list)
625625+626626+(provide process-data
627627+ format-result)
628628+629629+(define (process-data data)
630630+ ...)
631631+632632+(define (format-result result)
633633+ ...)
634634+```
635635+636636+---
637637+638638+## Third-Party Tools
639639+640640+These tools are widely used by Racketeers (the Racket community's name for themselves, in the Scheme tradition of naming things after illicit activities):
641641+642642+- **`raco fmt`** — automatic code formatting. Use this to ensure consistent formatting rather than hand-formatting.
643643+- **`resyntax`** — analyzes Racket code and suggests idiomatic improvements. Powered by `syntax-parse`-based refactoring rules. Useful for both learning idiomatic Racket and automated code cleanup.
644644+- **`raco cover`** — generates code coverage reports from tests. Helps identify untested code paths.
645645+646646+---
647647+648648+## Pitfalls Checklist
649649+650650+Before submitting Racket code, verify:
651651+652652+- [ ] File starts with `#lang racket` (or appropriate language)
653653+- [ ] Square brackets used in cond, match, let, for, parameterize clauses
654654+- [ ] No closing parens on their own line
655655+- [ ] Using `for/list` etc. instead of manual recursion where appropriate
656656+- [ ] Using `in-list`, `in-vector`, etc. in for clauses
657657+- [ ] Kebab-case naming throughout (no snake_case, no camelCase)
658658+- [ ] Predicates end in `?`, mutators in `!`, conversions use `->`
659659+- [ ] `define` used instead of `let*` where possible in function bodies
660660+- [ ] Structs use `#:transparent` unless there's a reason not to
661661+- [ ] Tests in `module+ test` submodules (even in test/ directories)
662662+- [ ] `require` and `provide` at the top of the file
663663+- [ ] No unnecessary dependencies (use `racket/base` + explicit requires for libraries)
664664+- [ ] Errors raised with `raise-argument-error` / `raise-arguments-error`, not `error`
665665+- [ ] Macros use `syntax-parse`, not `syntax-rules` or `syntax-case`