Перейти к основному содержимому

Clojure — о разделе

Черновик раздела. Материалы будут дополняться; ниже — структура раздела, ключевые идеи и черновые статьи с уже полезным содержанием для старта.

Clojure — современный диалект Lisp, компилируемый в байткод JVM (также ClojureScript для JS и Clojure CLR для .NET). Язык сочетает:

  • неизменяемые структуры данных (vector, map, set);
  • REPL-first workflow — разработка через интерактивную консоль;
  • макросы — расширение языка без форка компилятора;
  • interop с Java — вызов любого Java-класса из Clojure.

Раздел ориентирован на Clojure на JVM (tools.deps, Leiningen, Clojure CLI).

Общая база — Что такое код и как он работает.

МатериалЗачем
История языкаRich Hickey, идеи immutability
Первая программаREPL, deps.edn, Hello World
Java — о разделеRuntime и библиотеки
Lisp — о разделеS-expressions и macros

Что такое Clojure простыми словами

Clojure работает на JVM — той же виртуальной машине, что и Java. Вы пишете код в скобочной нотации Lisp, получаете доступ к миллионам Java-библиотек и деплоите JAR или uberjar.

Отличие от Java и Scala:

АспектJavaScalaClojure
ПарадигмаОО, классыОО + FP, типыFP, данные + функции
Синтаксисфигурные скобкиScala-синтаксисS-expressions (f x y)
Состояниеmutable поляvar/val, implicitsatoms, refs, immutability
REPLвториченестьцентр workflow

Clojure прагматичен: это функциональный язык на JVM, а не pure FP как Haskell — допускаются side effects через явные механизмы (atom, IO через host).


Планируемое содержание

ТемаСтатус
1История языкачерновик
2Основы — синтаксис S-expressions, типы, коллекциипланируется
3Функции, замыкания, lazy seqпланируется
4STM, atoms, refs, agentsпланируется
5Макросы и метапрограммированиепланируется
6Java interop, deps.edn, Leiningenпланируется
7Первая программачерновик
8+ClojureScript, Datomic, практикумыпланируется

Ключевые идеи раздела

Неизменяемые коллекции

(def users [{:id 1 :name "Anna"} {:id 2 :name "Bob"}])
(conj users {:id 3 :name "Carol"}) ; новая vector, старая не меняется

Persistent data structures дают structural sharing — новая версия переиспользует части старой без полного копирования.

REPL как основной инструмент

Разработчик оценивает выражения в REPL, наращивает функции инкрементально, подключает namespace из файлов. Файл .clj служит модулем для организации кода; стартовать можно прямо из REPL.

Identity и state

Изменяемое состояние во времени моделируют через identity (логическая сущность) и state (значение в момент времени):

  • atom — swap! для одиночного значения;
  • ref — транзакции STM;
  • agent — асинхронные обновления.

Подробные статьи по concurrency — в планируемых главах 4–6.

Java interop

(.format (java.text.SimpleDateFormat. "yyyy-MM-dd") (java.util.Date.))

Любой Maven-артефакт из deps.edn доступен без генерации обёрток.


Инструменты экосистемы

ИнструментНазначение
Clojure CLIclojure, clj, deps.edn
LeiningenКлассический build, lein new, lein repl
tools.depsДекларативные зависимости в EDN
nREPLСетевой REPL для IDE
Calva / CursiveVS Code и IntelliJ

Современные проекты часто начинают с deps.edn; legacy — Leiningen. Обе модели coexist — в первой программе разобран Clojure CLI.


ClojureScript и смежные темы (план)

ClojureScript — тот же язык, компиляция в JavaScript. Популярны Reagent, re-frame для SPA. Datomic — база данных от автора Clojure с моделью immutable facts. Эти темы — в главах 8+ после JVM-базы.


Порядок чтения

  1. История языка — контекст и мотивация Rich Hickey.
  2. Первая программа — REPL, deps.edn, -main.
  3. Основы и коллекции (когда появятся статьи 2–3).
  4. Concurrency и interop с Java (статьи 4–6).

Для сравнения JVM-языков параллельно полезны Scala intro и Java intro.


Кому подойдёт раздел

Clojure привлекает команды, которым нужны функциональная модель и JVM-экосистема без тяжёлого ОО-шаблонного кода enterprise-стиля.

СценарийПочему Clojure
Backend на JVM с простой моделью данныхMaps и vectors вместо иерархий классов
Data pipeline, ETLImmutable transforms, transducers
Legacy Java + новый модульInterop без переписывания
Fullstack (Clojure + ClojureScript)Общие структуры данных

Вакансии реже, чем Java/Kotlin, но стабильны в fintech, стартапах с data-oriented design и open source (Metabase, Penpot ecosystem).


Связанные разделы энциклопедии

Язык / темаСвязь
LispПредок синтаксиса и macros
JavaRuntime, hiring pool библиотек
ScalaАльтернативный FP на JVM
HaskellТеория immutability и типов
Черновик

Статьи 2–6 и ClojureScript пока в плане. Черновики истории и первой программы уже содержат рабочие команды и примеры для локального старта.


Экосистема JVM вокруг Clojure

Clojure не изолирован: он компилируется в JVM bytecode и вызывает Java-классы без обёрток. Типичный backend-стек:

СлойТехнология
HTTPRing, Compojure, Reitit, Pedestal
Persistencenext.jdbc, HugSQL, Datomic (отдельный продукт)
Asynccore.async, manifold
ConfigEDN, Aero, cprop
Builddeps.edn, Leiningen, tools.build

Зависимости из Maven Central подключаются в deps.edn — см. пакетные менеджеры.


Clojure и другие JVM-языки

КритерийJavaKotlinScalaClojure
ПарадигмаОООО + FPFP + OОFP, data-first
СинтаксисverboseconciseScalaS-expressions
REPLвториченестьестьцентр workflow
NullNPEnullable typesOptionnil + spec

Clojure выбирают, когда нужна простая модель данных (maps/vectors) и interop с Java, но не нужен типовый гигантизм Scala.


Transducers и производительность

Transducers — композиция трансформаций без промежуточных коллекций:

(def xf (comp (filter odd?) (map inc) (take 5)))
(into [] xf (range 100))

Идея Rich Hickey — отделить что делать с элементами от куда складывать. Полезно в ETL и stream processing на JVM.


Spec и контракты данных

clojure.spec (или Malli) описывает форму данных для валидации и generative testing:

(s/def ::email (s/and string? #(re-matches #".+@.+" %)))
(s/def ::user (s/keys :req-un [::email ::name]))

Spec не заменяет статическую типизацию Haskell, но ловит ошибки на границах API и в REPL-driven разработке.


Типичные ошибки новичков

ОшибкаСимптомСовет
(def x (conj x 1))Путаница var vs valuedef — top-level binding; локально let
Lazy seq без realizeStack overflow / hangdoall, vec, limit
Mutable Java object в atomRaceImmutable maps внутри atom
Giant defn без decompositionНечитаемый кодМалые pure functions

Сообщество и ресурсы

РесурсСодержание
clojure.orgОфициальная документация
ClojureVerse / r/ClojureОбсуждения
Clojure for the Brave and TrueБесплатная книга для старта
Programming Clojure (Pragmatic)Глубже про экосystem

Конференции: Clojure/conj (US), :clojureD (EU). Вакансии концентрируются в fintech, data, open source (Metabase).


Безопасность и деплой

  • Uberjar — один JAR со всеми deps для java -jar app.jar.
  • Secrets — env vars, не EDN в git; см. конфигурации.
  • AOT compile — ускорение cold start; trade-off с dynamic REPL в prod.

Чек-лист перед первой программой

  • Установлен JDK 17+ (LTS)
  • clojure -Sdescribe показывает версию CLI
  • Прочитана история — контекст immutability
  • Открыт REPL и выполнен (+ 1 2)

Сравнение JVM-языков для новичка

КритерийJavaKotlinScalaClojure
СинтаксисЗнакомый C-styleСовременныйГибкий, сложныйСкобки Lisp
REPLjshell (позже)kotlincscalaцентр workflow
Null safetyOptionalвстроенаOptionnil messaging
Learning curveсредняясредняявысокаяскобки + FP

Clojure выбирают, когда команда уже ценит immutability и data-oriented design, а не когда нужен максимальный hiring pool.


Типичный стек Clojure-проекта

СлойТехнология
HTTPRing, Reitit, Pedestal
HTMLHiccup (server-side)
FrontendClojureScript + Shadow-cljs
БДnext.jdbc, Datomic (niche)
Asynccore.async
ConfigEDN files, aero

Статьи по каждому компоненту появятся в главах 8+.


Как читать S-expressions

(max 3 (+ 1 2))

Читается изнутри наружу: (+ 1 2) → 3, затем (max 3 3) → 3. Оператор всегда первый в списке — prefix notation.


Ресурсы сообщества

РесурсURL
Официальный сайтclojure.org
ClojureDocsclojuredocs.org
Slack / Zulipcommunity links на clojure.org
4Clojureупражнения для новичков


Второй проход — transducers и spec (черновик)

Transducers (кратко)

Transducers — композиция трансформаций без промежуточных коллекций:

(require '[clojure.core :refer [comp map filter into transduce]])

(def xf (comp (map :score) (filter #(> % 50))))
(transduce xf + [{:score 40} {:score 80} {:score 60}])
;; => 140

Идея из Clojure 1.7+ — эффективные data pipeline; подробная статья в планируемой главе 4.

clojure.spec (обзор)

spec описывает форму данных для валидации и генерации тестов:

(require '[clojure.spec.alpha :as s])

(s/def ::email (s/and string? #(re-find #"@" %)))
(s/def ::user (s/keys :req-un [::email]))

(s/valid? ::user {:email "a@b.c"}) ; true

В полной версии раздела — generative testing с clojure.test.check.

Безопасность deps.edn

Не подключайте произвольные Git-координаты без ревью. SHA-pin для :git/url deps в командных проектах. См. конфигурации.


FAQ раздела

Clojure или Scala на JVM? Clojure — FP и data; Scala — типы и ОО+FP — Scala intro.

Нужен ли Java до Clojure? Базовое понимание JVM и Maven coords помогает; синтаксис Java не обязателен.

Leiningen или deps.edn? Новые проекты — deps.edn; legacy — Leiningen.

ClojureScript когда? Fullstack после JVM-базы — глава 8+.

Hiring niche? Fintech, data startups, Metabase ecosystem.

Lisp обязателен? Полезен контекст — Lisp intro.

Pure FP? Нет — atoms, side effects через host явно.

IDE? Calva, Cursive, CIDER — REPL-first.

Breaking changes? Редки; 1.x совместимость сильная.

Datomic required? Нет — отдельный продукт того же автора.

Babashka vs JVM? Scripts vs long-running services.

spec vs Malli? Обе validate; Malli популярнее в новых libs.

Transducers? Композиция без промежуточных seq — см. выше.

Java interop pain? Dot notation; occasional type hints.

Next read? 1.md, 7.md.


Упражнения для самопроверки (раздел)

  1. Запустите clojure и вычислите (reduce + (range 10)).
  2. Создайте deps.edn с одной зависимостью cheshire и распарсьте JSON.
  3. Объясните разницу def, defn, let.
  4. Найдите в документации описание atom и swap!.
  5. Прочитайте историю Rich Hickey и выпишите три идеи immutability.