Racket — диалект Lisp, выросший из Scheme, и самостоятельная платформа: язык, среда разработки, менеджер пакетов и библиотеки. Его используют в университетах, в исследованиях языков и в прикладных проектах — от скриптов до веб-сервисов. Синтаксис минимален, а инструменты показывают, как программа выполняется шаг за шагом. Для преподавателя это меньше времени на скобки и больше — на алгоритмы. Для разработчика — макросы, контракты и единый raco.
Почему Racket выбирают для обучения
В Racket почти нет синтаксического шума. Вызов всегда выглядит как (имя аргументы...), поэтому не нужно запоминать приоритеты операторов. Ошибки приходят с указанием функции и выражения, а не с длинным стеком фреймворка.
DrRacket добавляет пошаговый stepper, проверку синтаксиса до запуска и уровни языков. Начинающий работает в учебном диалекте с ограниченным набором конструкций, а затем переходит к полному #lang racket без переписывания привычек.
Платформа не заканчивается учёбой. Библиотеки покрывают HTTP, JSON, базы данных, парсинг и графику, а макросы позволяют строить предметно-ориентированные языки без генератора кода. Отдельные пакеты помогают встроить Racket как скриптовый язык в существующее приложение.
Установка и проверка
В Debian и Ubuntu есть пакет racket, но версия в репозитории может отставать. Для занятий этого достаточно; для новых библиотек лучше поставить официальный дистрибутив. Проверьте версию и наличие DrRacket.
sudo apt update
sudo apt install racket
racket --version
raco pkg install --auto drracket
raco pkg install ставит пакеты в пользовательский каталог без root. Если DrRacket уже входит в поставку, повторная установка ничего не сломает. drracket открывает среду, racket — REPL. Быстрая проверка: racket -e '(+ 1 2)'.
Первый код: REPL и файл
Начните с интерактивной сессии: она показывает результат каждого выражения сразу. В файле добавьте #lang racket первой строкой, а в REPL определения вводите без неё.
(require racket/list)
(define (square x) (* x x))
(square 7)
(map square '(1 2 3 4))
(filter even? '(1 2 3 4 5 6))
(foldl + 0 '(1 2 3 4))
Обратите внимание на апостроф: '(1 2 3) — литерал списка, а не вызов функции. Скобки группируют выражения, а не задают порядок операций. После нескольких примеров синтаксис перестаёт мешать.
Структуры и сопоставление с образцом
Структуры объявляются одной формой и получают конструктор, предикат и аксессоры. Флаг #:transparent делает значения читаемыми в REPL и тестах. Сопоставление с образцом заменяет цепочки условий.
#lang racket
(struct point (x y) #:transparent)
(define p (point 3 4))
(point-x p)
(match p
[(point 0 0) "начало координат"]
[(point x y) (sqrt (+ (* x x) (* y y)))])
match проверяет форму данных и связывает переменные. Если образец не подошёл, возникает ошибка с перечнем вариантов — это удобнее молчаливого else.
Модули, контракты и тесты
Файл на Racket — это модуль. provide экспортирует нужные функции, а contract-out проверяет значения на границе модуля. Контракты не заменяют статическую типизацию, но ловят ошибки вызова раньше.
#lang racket
(provide (contract-out [area (-> number? number?)]))
(define (area r) (* pi r r))
(module+ test
(require rackunit)
(check-equal? (area 2) (* 4 pi)))
Блок module+ test выполняется только при тестировании. Для строгой проверки типов есть #lang typed/racket: тот же язык с аннотациями и статическим анализом. Начинать лучше с обычного Racket.
Макросы без магии
Макрос — функция, работающая на этапе компиляции и возвращающая новое выражение. Гигиена переименовывает локальные переменные, поэтому макрос не ломает код вызывающей стороны. Пример — свой unless.
#lang racket
(define-syntax-rule (unless condition body ...)
(when (not condition) body ...))
(unless (= 1 2)
(displayln "условие ложно"))
Макросы применяйте для повторяющегося каркаса, а не для экономии символов. Если правило выражается функцией, начните с функции: её проще тестировать.
Небольшой веб-сервер
В стандартной поставке есть веб-сервер. Пара строк поднимает обработчик, возвращающий HTML. Удобный учебный проект: видно, как запрос превращается в ответ.
#lang racket
(require web-server/servlet
web-server/servlet-env)
(define (start req)
(response/xexpr
'(html (head (title "Racket"))
(body (h1 "Привет из Racket")))))
(serve/servlet start #:port 8080 #:servlet-path "/")
Запустите racket server.rkt и откройте http://localhost:8080. Для задания достаточно формы и вывода списка. Для production нужны reverse proxy и управление процессами.
raco: единый инструмент
raco объединяет пакеты, компиляцию, тесты, сборку бинарников и документацию. Поэтому Racket ощущается платформой, а не интерпретатором.
raco test .
raco make main.rkt
raco exe -o app main.rkt
raco scribble --htmls doc.scrbl
raco test находит тесты, raco make компилирует байткод, raco exe собирает исполняемый файл, raco scribble делает HTML или PDF. Документация остаётся рядом с кодом.
Как строить занятия
Методика HtDP предлагает проектировать функцию по шагам: сигнатура и назначение, примеры, шаблон, тело, тесты. В DrRacket каждый шаг виден на экране. Студент наблюдает не только результат, но и процесс вычисления.
- начинайте с чисел, строк и списков;
- показывайте stepper на рекурсии и
match; - давайте задачи на обработку списков без циклов;
- вводите структуры для данных из нескольких полей;
- заканчивайте проектом: парсер, игра или веб-форма;
- проверяйте тесты до обсуждения стиля.
Главная трудность — не скобки, а рекурсивное мышление. Помогают маленькие примеры, явные шаги и привычка сначала писать тесты. Racket показывает цену побочных эффектов: чистая функция короче и понятнее.
Итог
Racket стоит рассматривать, если вы учите программированию, исследуете языки или хотите предсказуемую семантику и метапрограммирование. Это не лучший способ написать CRUD, зато один из лучших — понять устройство языков. Начните с DrRacket, stepper и списков, затем соберите проект через raco.
- поставьте Racket и DrRacket, проверьте
racket --version; - освойте REPL и префиксную запись;
- добавьте структуры,
matchи контракты; - напишите тесты через
rackunitиraco test; - соберите учебный веб-сервер или парсер;
- оформите документацию в Scribble.