From 5ad9fb37181da151a7a939a3c6a6f88d1020928d Mon Sep 17 00:00:00 2001 From: "Dhanji R. Prasanna" Date: Thu, 15 Jan 2026 07:20:42 +0530 Subject: [PATCH] Improve carmack.racket.md with code examples and Racket-specific guidance Changes: - Add concrete code examples for match/cond and contract-out - Add Phase separation section (for-syntax vs runtime) - Add Continuations section (call/ec over call/cc, parameterize) - Add Concurrency section (places, threads, channels, sync) - Add Gotchas section (eq?/equal?/eqv?, null?/empty?, string=?) - Tighten Packages/tooling (raco pkg install --auto, info.rkt) Removed generic advice: - 'Don't swallow exceptions' (obvious) - 'Add docstrings/comments' (obvious) - 'Include runnable examples' (obvious) - 'Optimize the bottleneck only' (obvious) - Entire 'Output expectations' section (meta, not Racket-specific) - Removed oddly specific 'file/sha1, file-watch' reference --- prompts/langs/carmack.racket.md | 124 +++++++++++++++++++------------- 1 file changed, 76 insertions(+), 48 deletions(-) diff --git a/prompts/langs/carmack.racket.md b/prompts/langs/carmack.racket.md index 2404c8a..8957af9 100644 --- a/prompts/langs/carmack.racket.md +++ b/prompts/langs/carmack.racket.md @@ -1,60 +1,88 @@ -RACKET-SPECIFIC GUIDANCE (apply by default) +Prefer **obvious, readable Racket** over cleverness. -- Prefer idiomatic Racket: - - Use `match` / `match-define` for destructuring. - - Use `for/*` loops and sequences instead of manual recursion unless recursion is clearer. - - Use `cond`, `case`, `and`, `or` cleanly; avoid nested `if` pyramids. - - Use immutable data by default; reach for mutation only when it materially improves clarity/perf. +## Keep control flow clean +```racket +;; Good: match for destructuring +(match-define (list name age) (get-user-info id)) -- Modules and structure: - - Organize code into small modules with explicit `provide` lists (prefer `provide (contract-out ...)` when exporting). - - Avoid `provide (all-defined-out)` except in quick prototypes/tests. - - Prefer `require` with explicit identifiers; avoid huge wildcard imports. +;; Good: cond over nested if +(cond + [(empty? items) '()] + [(special? (first items)) (handle-special items)] + [else (process-normal items)]) +``` +- Use `match` / `match-define` for destructuring. +- Use `for/*` loops and sequences instead of manual recursion unless recursion is clearer. +- Use `cond`, `case`, `and`, `or` cleanly; avoid nested `if` pyramids. +- Use immutable data by default; reach for mutation only when it materially improves clarity/perf. -- Contracts and types: - - If in untyped Racket: add contracts at module boundaries for public APIs (`contract-out`), especially for callbacks and data shapes. - - If the project uses `typed/racket`, keep typed/untyped boundaries clean and document them. - - Use predicates + struct definitions to make data models explicit. +## Modules: explicit exports +```racket +;; Good: explicit contract-out +(provide + (contract-out + [process-data (-> input/c output/c)])) -- Data modeling: - - Prefer `struct` (possibly `#:transparent`) for domain objects, not ad-hoc hash soup. - - For enums/variants: consider `struct` variants + `match`, or symbols with clear validation. - - For “records loaded from YAML/JSON”: validate once at the boundary; keep internal representation consistent. +;; Bad: leaky exports +(provide (all-defined-out)) +``` +- Organize code into small modules with explicit `provide` lists. +- Prefer `contract-out` when exporting public APIs. +- Avoid `provide (all-defined-out)` except in quick prototypes/tests. +- Prefer `require` with explicit identifiers; avoid huge wildcard imports. -- Error handling: - - Use `raise-argument-error`, `raise-user-error`, or `error` with a clear message. - - Wrap IO and parsing with `with-handlers` and rethrow with context (what file, what phase). - - Don’t swallow exceptions; surface actionable diagnostics. +## Contracts and types +- If in untyped Racket: add contracts at module boundaries for public APIs, especially for callbacks and data shapes. +- If the project uses `typed/racket`, keep typed/untyped boundaries clean and document them. +- Use predicates + struct definitions to make data models explicit. -- IO, paths, and portability: - - Use `build-path`, `simplify-path`, `path->string` as needed; don’t concatenate path strings manually. - - Use `call-with-input-file` / `call-with-output-file` and ports idiomatically. - - Prefer `file/sha1`, `file-watch`-style libs (if present) for reload tooling; otherwise design a simple polling fallback. +## Data modeling +- Prefer `struct` (possibly `#:transparent`) for domain objects, not ad-hoc hash soup. +- For enums/variants: consider `struct` variants + `match`, or symbols with clear validation. +- Validate external data (YAML/JSON) once at the boundary; keep internal representation consistent. -- Performance + allocations: - - Prefer vectors for hot loops / indexed access; lists for iteration; hashes for keyed lookup. - - Use `for/fold` or `for/hash` to build results efficiently. - - Avoid repeated `append` in loops; accumulate then reverse if needed. - - If profiling is needed: use `profile` or `time`, and optimize the bottleneck only. +## Error handling +- Use `raise-argument-error`, `raise-user-error`, or `error` with a clear message. +- Wrap IO and parsing with `with-handlers` and rethrow with context (what file, what phase). -- Macros and syntax: - - Don’t write macros unless it meaningfully reduces boilerplate or enforces invariants. - - If writing macros: use `syntax-parse` (not raw `syntax-case`) and include good error messages. - - Keep macro output readable and debuggable. +## IO and paths +- Use `build-path`, `simplify-path`, `path->string`; don't concatenate path strings manually. +- Use `call-with-input-file` / `call-with-output-file` idiomatically. -- Testing + docs: - - Add `rackunit` tests for tricky logic; prefer table-driven tests. - - When writing public APIs, add docstrings/comments; if there’s a lib boundary, consider Scribble docs. - - Include runnable examples in comments when it helps. +## Performance +- Prefer vectors for hot loops / indexed access; lists for iteration; hashes for keyed lookup. +- Use `for/fold` or `for/hash` to build results efficiently. +- Avoid repeated `append` in loops; accumulate then reverse if needed. -- Concurrency/events (common in engines/tools): - - Prefer clear event loops and message passing; avoid shared mutable state unless protected. - - If using parameters (`parameterize`), keep scope tight and document effects. +## Macros: use sparingly +- Don't write macros unless it meaningfully reduces boilerplate or enforces invariants. +- If writing macros: use `syntax-parse` (not raw `syntax-case`) and include good error messages. +- Keep macro output readable and debuggable. -- Packages/tooling: - - Assume `raco fmt` / `racket-format` style; keep formatting consistent. - - If suggesting deps, name the package and `raco pkg install` usage. +## Phase separation +- Understand `for-syntax` vs runtime; don't accidentally pull runtime values into macros. +- Use `begin-for-syntax` sparingly; prefer `syntax-local-value` patterns when possible. -- Output expectations: - - When proposing code changes, include: new/changed function signatures, required `require`s, and small usage examples. - - If unsure about a library’s availability, provide a fallback approach that uses base Racket. \ No newline at end of file +## Continuations: use sparingly +- Prefer `call/ec` (escape continuations) over full `call/cc` when possible. +- Use `parameterize` for dynamic scope, not continuation tricks. +- If using `parameterize`, keep scope tight and document effects. + +## Concurrency +- Use `place`s for CPU parallelism, `thread`s for I/O concurrency. +- Prefer channels (`make-channel`, `channel-put`, `channel-get`) over shared state. +- Use `sync` and events for composable waiting. + +## Gotchas +- `eq?` vs `equal?` vs `eqv?`: use `equal?` by default for structural comparison. +- `null?` only works on proper lists; use `empty?` from `racket/list` for generics. +- `string=?` not `equal?` for string comparison in hot paths. + +## Testing +- Add `rackunit` tests for tricky logic; prefer table-driven tests. +- Consider Scribble docs for library boundaries. + +## Packages/tooling +- Assume `raco fmt` style; keep formatting consistent. +- Use `raco pkg install --auto` for dependency resolution. +- Prefer `info.rkt` for package metadata over ad-hoc scripts.