racket-programmer skill
언어 지향 프로그래밍, 매크로, contract, Typed Racket에 중점을 둔 Racket 전문가 수준의 프로그래밍 가이드를 제공합니다.
- GitHub 스타
- 9
- 파일
- 1
- 마지막 커밋
- 2026년 10월 13일
- 라이선스
- EPL-2.0
- 허용된 도구
- —
racket-programmer skill은 무엇을 하나요?
racket-programmer은(는) agent skill입니다. 언어 지향 프로그래밍, 매크로, contract, Typed Racket에 중점을 둔 Racket 전문가 수준의 프로그래밍 가이드를 제공합니다.
skill의 SKILL.md에서 생성된 요약입니다.
racket-programmer skill 정보
Racket 프로그래밍에 대한 전문가의 가이드를 찾는 개발자는 이 SKILL을 사용하여 언어 지향 설계와 프로덕션급 코드를 구현할 수 있습니다. 단순한 라이브러리가 아닌 언어로서 솔루션을 구축하는 철학에 집중하며, 사용자가 표준 매크로나 라이브러리를 사용하는 대신 커스텀 #lang을 구현해야 할 시점을 결정하도록 돕습니다. 이 SKILL은 문제 해결에 S-expression이 아닌 구문, 컴파일 타임 검증 또는 특화된 IDE 통합이 필요한지 여부에 따라 적절한 도구를 선택할 수 있는 구체적인 의사결정 프레임워크를 제공합니다.
언어 설계를 넘어, 이 SKILL은 Racket의 매크로 시스템에 대한 깊은 기술적 전문성을 제공하며, 특히 프로덕션용 매크로를 위해 syntax/parse 사용을 권장합니다. 또한 contract를 사용하여 모듈 경계를 정의하고 불변성 위반 시 원인을 규명하는 방법을 지원하며, struct와 class 중 무엇을 선택할지에 대한 가이드를 제공합니다. 성능이 중요하거나 대규모 유지보수가 필요한 작업의 경우, 타입 정교화를 위한 occurrence typing 사용법을 포함하여 Typed Racket을 구현하는 방법을 설명합니다. 이는 Racket CS를 다루는 엔지니어나 복잡한 매크로 위생(hygiene) 및 단계 분리(phase separation)를 다뤄야 하는 사용자에게 특히 유용합니다.
agent가 수행할 수 있는 작업
- 1커스텀 도메인 언어 설계문제가 새로운 #lang, reader extension, 또는 단순한 매크로 기반 라이브러리를 필요로 하는지 판단합니다.
- 2프로덕션급 매크로 구현syntax/parse를 사용하여 검증 기능과 명확한 에러 메시지를 포함하는 매크로를 생성합니다.
- 3모듈 경계 보안공개 API에 contract-out을 적용하여 실행 가능한 명세를 보장하고 불변성 위반 시 원인을 규명합니다.
- 4타입을 통한 성능 최적화수치 계산 코드나 대규모 리팩토링을 위해 Typed Racket으로 전환해야 할 시점을 결정합니다.
skill의 SKILL.md를 기반으로 작성되었습니다. 모든 사용 사례는 해당 문서의 인용구와 대조 확인되었습니다.
racket-programmer skill 설치 방법
각 명령은 skill 폴더를 클라이언트의 skills 디렉터리에 복사합니다. 클라이언트를 재시작하거나 새 세션을 시작하여 로드하세요.플러그인에 racket-programmer skill 설치
/plugin marketplace add Pyroxin/opinionated-claude-skills /plugin install opinionated-lisp-development@opinionated-claude-skills
Claude Code에 racket-programmer skill 설치
~/.claude/skills/racket-programmer/SKILL.md
$ npx degit Pyroxin/opinionated-claude-skills/opinionated-lisp-development/skills/racket-programmer ~/.claude/skills/racket-programmerClaude Code (project)에 racket-programmer skill 설치
.claude/skills/racket-programmer/SKILL.md
$ npx degit Pyroxin/opinionated-claude-skills/opinionated-lisp-development/skills/racket-programmer .claude/skills/racket-programmerCodex에 racket-programmer skill 설치
~/.agents/skills/racket-programmer/SKILL.md
$ npx degit Pyroxin/opinionated-claude-skills/opinionated-lisp-development/skills/racket-programmer ~/.agents/skills/racket-programmerGemini CLI에 racket-programmer skill 설치
~/.gemini/skills/racket-programmer/SKILL.md
$ npx degit Pyroxin/opinionated-claude-skills/opinionated-lisp-development/skills/racket-programmer ~/.gemini/skills/racket-programmerClaude.ai에 racket-programmer skill 설치
npx degit Pyroxin/opinionated-claude-skills/opinionated-lisp-development/skills/racket-programmer racket-programmer && zip -r racket-programmer.zip racket-programmer # claude.ai → Customize → Skills → + → Create skill → Upload a skill → racket-programmer.zip
SKILL.md
GitHub에서 보기Racket Programmer
Expert-level Racket programming skill focused on judgment frameworks, language-oriented programming philosophy, and production practices.
Related skills:
software-engineer- Core programming philosophy and SICP principles that underpin Racket's designfunctional-programmer- FP patterns and thinking (Racket is fundamentally functional)test-driven-development- General testing philosophy; this skill covers RackUnit specifics
Version Targeting
Always target the latest stable Racket version unless explicitly working on a codebase with version constraints.
- Latest stable: Racket 8.18 (as of August 2025)
- Download: https://download.racket-lang.org/
- Version history: https://github.com/racket/racket/releases
- For historical context: https://en.wikipedia.org/wiki/Racket_(programming_language)#History
Racket CS (Chez Scheme-based) is the default implementation since 8.0. Strong backward compatibility commitment means minimal version fragmentation.
For owned codebases: Aggressive upgrade philosophy. Use latest features and libraries.
For third-party codebases: Respect existing version targets and conventions. When contributing to open source, follow the project's existing standards. Don't introduce modern features to projects targeting older versions. Propose improvements through proper channels (issues, governance).
<language_oriented_programming>
Language-Oriented Programming: Racket's Core Philosophy
Central Insight: Racket's defining characteristic is building solutions as languages, not just libraries. Every problem is approached by asking "what's the right notation?" before "what's the implementation?"
This is not a feature of Racket—it IS Racket's design philosophy. Understanding this distinction separates using Racket from merely writing Scheme with extra features.
From "The Racket Manifesto" (Felleisen et al., SNAPL 2015)
"A programmable programming language." Racket is designed to let programmers create languages tailored to specific problem domains. The language grows through the creation of new languages, not just new libraries.
Key principle: "If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization." —Gerald Weinberg
The right notation eliminates entire classes of errors at compile time. Language design is not an esoteric activity—it's the solution to the problem of making correct code easy to write and incorrect code hard to write.
Decision Framework: #lang vs Library vs Macro
Does solution need non-S-expression syntax?
→ Reader extension needed → #lang
Does solution benefit from compile-time validation of entire program?
→ Custom #%module-begin → #lang
Just adding new operations/abstractions?
→ Macros + provide → library
Need IDE integration (syntax coloring, specialized checks)?
→ #lang with language info
Notation precision outweighs learning curve?
→ #lang
When Language-Oriented Design Excels
- Novice interfaces - Create simpler notations for less-skilled programmers (HtDP teaching languages)
- Simplified notation - Regular expressions, configuration DSLs where domain notation is clearer
- Existing notation - BNF grammars (brag package), standard formats that users already know
- Intermediate compilation targets - JSON with embedded computation, specialized formats
- Configuration-heavy domains - Test specifications, API definitions where structure matters
Essential Reading:
- Beautiful Racket: https://beautifulracket.com/ (comprehensive LOP tutorial—read this)
- "Why Language-Oriented Programming?": https://beautifulracket.com/appendix/why-lop-why-racket.html
- "Creating Languages in Racket" (Flatt): https://queue.acm.org/detail.cfm?id=2068896
Trade-offs:
- ✅ Perfect notation-to-problem fit, early error detection via compiler, domain expert usability
- ❌ Learning curve, infrastructure maintenance overhead, tooling support complexity
- Decision heuristic: Use when minimum notation with maximum precision is critical
Language Towers: Composable Language Abstractions
Pattern: Build languages on languages, creating towers where each layer provides abstractions for the next. Unlike traditional macros that compete, Racket macros cooperate through shared compile-time information.
Key Paper: "Macros that Work Together" (Flatt et al., 2012)
Racket achieves this through:
- Partial expansion: Macros can expand sub-forms partially, inspect results, continue with additional context
- Definition contexts: Macros cooperate by maintaining lexical scope through hygiene
- Phase separation: Compile-time vs runtime code cleanly separated
Example: Racket's class system is implemented as macros over struct, which is itself a macro. Each layer maintains proper scoping and composition.
This is a fundamental difference from other Lisp macro systems where macros often interfere with each other. </language_oriented_programming>
<contracts_and_blame>
Code as Contracts: Module Boundaries and Blame
Core Pattern: Modules are units of abstraction AND units of blame for contracts. Design module boundaries intentionally with this in mind.
Contracts in Racket are not optional documentation—they are executable specifications that assign blame when violated. This is fundamentally different from assertions (which blame the entire program) or types (which reject programs statically).
Contract-Out: The Standard Pattern
(provide
(contract-out
[my-function (→ number? (>/c 0) boolean?)]
[my-struct (struct/c point [real? real?])]
[complex-fn (→i ([x number?]
[y (x) (>/c x)]) ; dependent contract
[result number?])]))
Decision Framework for Contracts
Public API boundary?
→ REQUIRED: contract-out with precise contracts
Internal module function?
→ Optional: Consider for complex invariants
Performance-critical inner loop?
→ Profile first (contracts typically cheap, but measure)
Complex invariant (e.g., balanced tree)?
→ Use dependent contracts (→i)
Simple type-like guarantee?
→ Flat contracts (number?, string?)
Contract Hierarchy
- Always: Module boundaries (public APIs) - MANDATORY for production
- Often: Complex data structures with invariants
- Sometimes: Internal boundaries in large modules
- Rarely: Simple, obvious functions
Chaperone vs Impersonator Contracts:
- Chaperone: Monitoring only, guarantees no behavior change (preferred)
- Impersonator: Can change behavior, heavier weight
- Use chaperones unless you need interposition
Key Resources:
- Contracts Guide: https://docs.racket-lang.org/guide/contracts.html
- Contract Reference: https://docs.racket-lang.org/reference/contracts.html
- "Contracts for Higher-Order Functions" (Findler & Felleisen): Foundational paper </contracts_and_blame>
<macro_system>
Macro System: Production Standards
Decision Matrix
| Need | Tool | When to Use |
|---|---|---|
| Simple substitution | define-syntax-rule |
One-off macros, prototyping |
| Multiple patterns | syntax-rules |
Standard pattern matching, no validation |
| Validation + errors | syntax/parse |
Production macros (recommended) |
| Complex compile logic | define-syntax + procedure |
Programmatic code generation |
| Syntax templates | with-syntax, quasisyntax |
Building syntax from data |
Syntax/Parse: The Production Standard
(define-syntax (my-let stx)
(syntax-parse stx
[(_ ([var:id rhs:expr] ...) body:expr ...+)
#:fail-when (check-duplicate-identifier (syntax->list #'(var ...)))
"duplicate variable name"
#'(let ([var rhs] ...) body ...)]))
Why syntax/parse for production:
- ✅ Declarative pattern matching with side conditions
- ✅ Domain-specific error messages via
#:fail-when - ✅ Syntax classes enable reusable patterns
- ✅ Better than syntax-rules for anything non-trivial
Essential Resources:
- "Fear of Macros" (Greg Hendershott): https://www.greghendershott.com/fear-of-macros/all.html (best macro tutorial—read this)
- syntax/parse docs: https://docs.racket-lang.org/syntax/stxparse.html
- Macro debugger: https://docs.racket-lang.org/macro-debugger/
Hygiene: Racket macros are hygienic by default. This prevents variable capture but means you must understand syntax objects. Use datum→syntax only when intentionally breaking hygiene (rare cases like anaphoric macros).
Reader Extensions: High Power, High Cost
Decision Tree:
Modify single character interpretation?
→ Readtable (make-readtable)
Embedded DSL with different syntax?
→ Readtable + #reader
Complete language with custom notation?
→ #lang + reader module
Compatible with S-expressions?
→ DON'T use reader - use macros instead!
When to Extend Reader:
- Need non-S-expression syntax (BNF, JSON-like, etc.)
- Domain notation is well-established and incompatible with parens
- Target audience uncomfortable with S-expressions
- Notation is fundamentally incompatible with Lisp syntax
When NOT to:
- Macros suffice (most cases!)
- Syntax is still S-expressions with new forms
- Team not ready for the complexity
- Tool support matters more than notation
Trade-offs:
- ✅ Perfect notation for domain, can parse existing formats
- ❌ Complexity, harder debugging, less tool support, team must learn custom syntax </macro_system>
<structs_vs_classes>
Structs vs Classes: The 90/10 Rule
Decision Framework:
Representing data with operations?
→ Struct (90% of use cases)
Need inheritance-based polymorphism with method overriding?
→ Class
Building GUI application?
→ Class (Racket GUI framework uses classes)
Need polymorphism but not inheritance?
→ Struct with generic interfaces (#:methods gen:custom)
Porting OO codebase?
→ Class (but consider refactoring to structs)
Struct Advantages
- ✅ Lighter weight, faster
- ✅ Work with pattern matching
- ✅ Simpler mental model
- ✅ Can add methods via
#:methodswith generics - ✅ Transparent/opaque control
Class Use Cases
- Full OO with inheritance
- Method overriding, super calls
- Mixins and traits
- GUI programming (required by framework)
Hybrid Approach: Structs + Generic Interfaces
(define-generics printable
(print-it printable port))
(struct point (x y)
#:methods gen:printable
[(define (print-it p port)
(fprintf port "(~a,~a)" (point-x p) (point-y p)))])
Staff Guidance: Default to structs. Only use classes when working with GUI framework, need true inheritance, or building OO framework for others. When unsure, start with structs + generics. </structs_vs_classes>
<typed_racket>
Typed Racket: When and Why
Decision Framework
Performance-critical numeric code?
→ YES (25-50× speedups possible)
Large-scale refactoring/maintenance?
→ YES (types document invariants)
Complex data structure invariants?
→ YES (occurrence typing + refinements)
Heavy typed/untyped interaction?
→ CAUTION (contract overhead can be severe)
Exploratory/prototype code?
→ NO (friction not worth it)
Macro-heavy DSLs?
→ NO (limitations on macro usage)
Language Declaration
#lang typed/racket ; Deep types (default, full checking)
#lang typed/racket/shallow ; Shallow types (lower overhead)
#lang typed/racket/optional ; Optional types (no runtime cost)
Occurrence Typing (Unique Feature)
Racket's type system has occurrence typing—type refinement based on predicates:
(: flexible-length (→ (U String (Listof Any)) Integer))
(define (flexible-length x)
(if (string? x)
(string-length x) ; x refined to String here
(length x))) ; x refined to (Listof Any) here
This is a distinctive feature compared to most gradual type systems.
Performance Best Practices
- Use
FloatnotRealfor numeric optimization - Prefer structs to vectors (always optimized)
- Use typed versions of standard libraries
- Minimize boundary crossings
Essential Resources:
- Typed Racket Guide: https://docs.racket-lang.org/ts-guide/
- Contract Profiler: https://docs.racket-lang.org/contract-profile/
- Optimization Coach: https://docs.racket-lang.org/optimization-coach/ </typed_racket>
<functional_idioms>
Racket-Specific Functional Idioms
What Makes Racket FP Unique (not generic FP advice that you already know):
1. Contracts as First-Class Behavioral Specifications
Not just type checking; express behavioral constraints. Contracts are values that can be computed and composed.
2. Macros Enable Compile-Time FP
Compile-time computation is functional programming. Phase separation keeps concerns clean.
3. Parameters for Dynamic Binding
Better than global variables for cross-cutting concerns:
;; Standard pattern for context
(parameterize ([current-output-port (open-output-file "log.txt")])
(displayln "logged"))
Example: current-output-port, current-directory
4. Sequence Abstractions
;; Prefer for/* comprehensions over explicit recursion
(for/list ([x (in-range 10)]
#:when (even? x))
(* x x))
5. Match-Based Dispatch
(define (eval expr)
(match expr
[(? number? n) n]
[`(+ ,a ,b) (+ (eval a) (eval b))]
[`(* ,a ,b) (* (eval a) (eval b))]))
When to Mutate in Racket
- Algorithm is inherently stateful (union-find, hash table implementation)
- Performance-critical after profiling shows bottleneck
- Implementing imperative interface for interop
- Default: Prefer functional style at module boundaries, mutation only internally </functional_idioms>
<pattern_matching>
Pattern Matching: When and How
Use match when:
- Deconstructing structured data (lists, structs, syntax)
- Dispatch on data shape
- Working with recursive data structures
- Replacing verbose accessor chains
Don't use match for:
- Simple conditionals (use
condorif) - Single binding extraction (use
let) - Just checking predicates (use predicate directly)
Key Patterns:
;; Struct patterns
(match point
[(point x y) ...])
;; Quasiquote for S-expressions
(match expr
[`(if ,cond ,then ,else) ...])
;; Guards
(match x
[(? number? n) ...]
[(list a b) #:when (> a b) ...])
;; Or patterns
(match expr
[(or (list 'add x y) (list '+ x y)) ...])
</pattern_matching>
<tooling_and_standards>
Mandatory Tooling and Standards
#lang racket/base vs #lang racket (CRITICAL)
Decision Rule:
Production library code → #lang racket/base (REQUIRED)
Scripts/demos/exploration → #lang racket (acceptable)
Why racket/base for libraries:
- Faster startup (loads only core)
- Explicit dependencies (clearer what's needed)
- Smaller dependency footprint
- Better practice for maintainability
Quote from Beautiful Racket: "As a rule of thumb, it's better practice to start with racket/base and use require to import what you need."
raco fmt: The Automatic Formatter (Mandatory)
Installation: raco pkg install fmt
Usage:
raco fmt -i file.rkt # Format in-place
raco fmt --width 102 file.rkt # Custom width (style guide default)
raco fmt --check file.rkt # Check without modifying (CI usage)
CI Integration: Add raco fmt --check to fail builds on formatting violations
What it Enforces:
- Default 80-character width (use
--width 102for style guide compliance) - Max 1 consecutive blank line
- Converts to brackets
[...]in specific contexts:let,for,cond,match,case - Handles 183+ standard forms
raco review: Linting (Mandatory for CI)
Installation: raco pkg install review
Usage:
raco review file.rkt
raco review . # Review entire directory
What It Detects:
- Syntax errors
- Unused identifiers
- Variable shadowing
- Missing else clauses
- Incorrect require ordering
- Style issues
Ignoring Warnings:
#|review: ignore|# ; Ignore entire file
(define x 5) ;; review: ignore ; Ignore line
RackUnit: Testing (Mandatory)
For general testing philosophy, see the test-driven-development skill. Core principle: Tests are contracts that document expected behavior at module boundaries. This skill covers RackUnit-specific patterns.
Basic Usage:
(require rackunit)
;; Simple checks
(check-equal? actual expected "message")
(check-= actual expected epsilon)
(check-true value)
(check-pred predicate value)
(check-exn exn-predicate (thunk ...))
Test Suites:
(define my-tests
(test-suite
"Suite name"
(test-case "Test 1"
(check-equal? (foo 5) 10))
(test-case "Test 2"
(check-true (bar "test")))))
(run-tests my-tests)
module+ test Pattern:
#lang racket/base
(define (my-function x)
(+ x 1))
(provide my-function)
(module+ test
(require rackunit)
(check-equal? (my-function 5) 6)
(check-equal? (my-function 0) 1))
Running Tests:
raco test file.rkt # Test single file
raco test -p package-name # Test entire package
Scribble: Documentation (Mandatory for Production)
Basic Document Structure:
#lang scribble/manual
@(require (for-label racket my-lib))
@title{My Library}
@defmodule[my-lib]
@defproc[(my-function [arg1 string?] [arg2 integer?])
boolean?]{
Description of what the function does.
@examples[
#:eval my-eval
(my-function "hello" 42)
]
}
MANDATORY: All exported bindings in production code must have Scribble documentation.
Building:
scribble --html manual.scrbl
raco setup --doc-index --pkgs my-package
Code Style: Mandatory for Production
Official Style Guide
Primary Resource: https://docs.racket-lang.org/style/index.html
Critical Rules:
- Parentheses: ALL closing parens on LAST line (never on separate lines)
- Indentation: Use DrRacket's "indent all" as STANDARD (no tabs, spaces only)
- Line width: 102 characters maximum
- Naming: kebab-case with full English words (NOT camelCase, NOT snake_case)
- End files with newline, no trailing whitespace
Naming Conventions (Mandatory)
| Character | Meaning | Example |
|---|---|---|
? |
Predicates | boolean?, even? |
! |
Mutators | set!, vector-set! |
% |
Classes | button%, frame% |
<> |
Interfaces | dc<%>, window<%> |
^ |
Unit signatures | game-context^ |
@ |
Units | testing-context@ |
#% |
Kernel forms | #%app, #%module-begin |
/ |
"with" preposition | call/cc, for/list |
Standard Pattern: type-operation (e.g., string-append, hash-ref, list->vector)
File Organization
#lang racket/base ; Language line (first line)
;; Exports (provide forms first, ideally)
(provide (contract-out
[function (→ Type Type)]
[struct-name ...]))
;; Imports (require forms grouped)
(require racket/list
racket/match
(for-syntax racket/base))
;; Implementation
(define ...)
(struct ...)
Project Layout: The lib/test/doc Pattern
Multi-Collection Package Structure (Production Standard)
For non-trivial libraries:
my-library/
my-library-lib/ # Runtime code only
info.rkt
main.rkt
core/
module1.rkt
my-library-test/ # Tests only
info.rkt
tests/
test-module1.rkt
my-library-doc/ # Documentation only
info.rkt
scribblings/
my-library.scrbl
my-library/ # Composite meta-package
info.rkt # Aggregates all components
Why This Pattern:
- ✅ Focused dependencies - Apps depend only on
-lib, not test/doc deps - ✅ Minimizes failure points - Doc build failures don't break library installation
- ✅ Efficiency - Users download only what they need
- ✅ Flexibility - Can install just tests or just docs
Authoritative Resource: https://countvajhula.com/2022/02/22/how-to-organize-your-racket-library/
Single-Collection Package (Simple Projects)
For small libraries:
my-simple-lib/
main.rkt
helper.rkt
tests/
main-test.rkt
scribblings/
my-simple-lib.scrbl
info.rkt
Package Management: raco pkg
Core Commands:
raco pkg install package-name # From catalog
raco pkg install github://user/repo/branch
raco pkg update package-name
raco pkg update --all
raco pkg remove package-name --auto # Remove + unused deps
raco pkg show --all # List all packages
Declaring Dependencies in info.rkt (MANDATORY):
#lang info
(define deps
'("base" # Always required
"rackunit-lib"
"web-server-lib"
["other-package" "2.0"])) # Version constraint
(define build-deps
'("scribble-lib" # For docs
"racket-doc")) # For doc cross-refs
Key Fields:
deps: Runtime dependencies (REQUIRED)build-deps: Build-time only (tests, docs)implies: Re-exports for meta-packages </tooling_and_standards>
<ci_cd_integration>
CI/CD Integration (MANDATORY for Production)
GitHub Actions Standard Setup:
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
racket-version: ['8.16', '8.17', 'stable']
variant: ['CS']
steps:
- uses: actions/checkout@v3
- name: Setup Racket
uses: Bogdanp/setup-racket@v1.14
with:
architecture: 'x64'
distribution: 'full'
variant: ${{ matrix.variant }}
version: ${{ matrix.racket-version }}
- name: Install Dependencies
run: raco pkg install --auto --batch
- name: Check Dependencies
run: raco setup --check-pkg-deps --pkgs my-package
- name: Run Tests
run: raco test --package my-package
- name: Build Documentation
run: raco setup --doc-index --pkgs my-package
- name: Lint Code
run: |
raco pkg install --auto review
raco review .
- name: Check Formatting
run: |
raco pkg install --auto fmt
raco fmt --check .
What MUST Fail Builds:
- ✅
raco testfailures (REQUIRED) - ✅
raco setup --check-pkg-depsfailures (REQUIRED) - ✅
raco reviewviolations (RECOMMENDED) - ✅
raco fmt --checkfailures (if using formatter) - ✅ Documentation build failures (RECOMMENDED) </ci_cd_integration>
<common_mistakes>
Common Mistakes from Other Languages
<from_scheme>
From Scheme (R5RS/R6RS/R7RS)
Key Differences:
-
Immutable Pairs by Default: Racket pairs are immutable. No
set-car!/set-cdr!. Usemcons/mcar/mcdrfor mutable pairs. -
Module System: Racket's modules are NOT R6RS-compatible. Must use
#lang racketnot R6RS module syntax. -
Letrec Semantics: Racket's
letrecis sequential (like R6RSletrec*), not R5RSletrec. -
Case Sensitivity: Racket is case-sensitive by default (R5RS was case-insensitive).
-
Pattern Matching: Not in standard Scheme; heavily used in Racket. Learn
match.
Resources:
- Standards Compatibility: https://docs.racket-lang.org/guide/standards.html </from_scheme>
<from_common_lisp>
이 스킬의 파일
1racket-programmer skill 질문
Claude Code에 racket-programmer skill을 어떻게 설치하나요?
npx degit Pyroxin/opinionated-claude-skills/opinionated-lisp-development/skills/racket-programmer ~/.claude/skills/racket-programmer를 실행합니다. Claude Code는 ~/.claude/skills(모든 프로젝트) 또는 .claude/skills(한 프로젝트)에서 skills를 로드하며, 설명이 작업과 일치할 때 skill을 사용합니다.
racket-programmer skill을 사용할 수 있는 클라이언트는 무엇인가요?
Agent Skills 형식을 읽는 모든 클라이언트(Claude Code, Codex, Gemini CLI, claude.ai(ZIP으로 업로드))가 사용할 수 있습니다. skill 내 스크립트는 클라이언트가 코드 실행을 허용하는 경우에만 실행됩니다.
Racket에서 라이브러리 대신 #lang을 사용해야 하는 경우는 언제인가요?
S-expression이 아닌 구문이 필요하거나, 프로그램 전체의 컴파일 타임 검증이 필요할 때, 또는 특화된 IDE 통합이 필요할 때 #lang을 사용합니다.
Racket에서 프로덕션용 매크로를 작성하는 권장 방법은 무엇인가요?
프로덕션용 매크로에는 syntax/parse 사용을 권장합니다. 이는 부가 조건이 포함된 선언적 패턴 매칭과 도메인 특화 에러 메시지를 제공하기 때문입니다.
데이터 표현을 위해 struct를 사용해야 하나요, 아니면 class를 사용해야 하나요?
대부분의 경우 struct가 더 가볍고 빠르므로 90%의 상황에서는 struct를 사용해야 합니다. 상속 기반의 다형성, 메서드 오버라이딩이 필요하거나 GUI를 구축하는 경우에만 class를 사용합니다.
Typed Racket을 사용하는 것이 유리한 경우는 언제인가요?
Typed Racket은 성능이 중요한 수치 계산 코드, 대규모 리팩토링, 또는 복잡한 데이터 구조의 불변성(invariant)을 관리할 때 유용합니다.