feat: add Clojure/Nim chapter to the book + restructure for GitLab

- New chapter 05-clojure-nim.md (EN + BG) covering:
  - Native compilation pipeline (Clojure → Nim → C → binary)
  - AI-powered development (error explanation, code generation)
  - JSON REPL for AI agents
  - loop/recur with real TCO
  - Cross-compilation: JS, shared libs, WASM
  - Persistent data structures (HAMT)
  - Concurrency: atoms, agents, channels
- Updated book README.md with Clojure/Nim focus
- Added Clojure/Nim terms to subject indices (EN + BG)
- Removed books/ from .gitignore so it can be pushed to GitLab
This commit is contained in:
2026-05-08 23:32:11 +03:00
parent 10e4ec07d6
commit 23252826a0
14 changed files with 9386 additions and 1 deletions
File diff suppressed because it is too large Load Diff
+710
View File
@@ -0,0 +1,710 @@
# Чист Clojure: Разширени теми
## Съдържание
1. [Разширени функции](#1-разширени-функции)
2. [Мързеливи серии - задълбочено](#2-мързеливи-серии---задълбочено)
3. [Трансдюсъри](#3-трансдюсъри)
4. [Specs и валидация](#4-specs-и-валидация)
5. [Протоколът Collection](#5-протоколът-collection)
6. [Reducibles](#6-reducibles)
7. [Паралелизъм](#7-паралелизъм)
8. [Оптимизация на производителността](#8-оптимизация-на-производителността)
9. [Индекс](#9-индекс)
---
## 1. Разширени функции
### 1.1 Вариадични функции
Функциите могат да приемат променлив брой аргументи:
```clojure
(defn print-all [& args]
(doseq [arg args]
(println arg)))
(print-all "a" "b" "c")
;; С задължителни аргументи
(defn greet [name & greeting-parts]
(str (clojure.string/join " " greeting-parts) ", " name "!"))
(greet "World" "Hello" "Good morning") ;; => "Hello Good morning, World!"
```
### 1.2 Rest параметри в детайли
Символът `&` улавя останалите аргументи като серия:
```clojure
(defn my-apply [f & args]
(apply f args))
;; Използване с деструктуриране
(defn first-two [[a b & rest]]
{:first a :second b :rest rest})
(first-two [1 2 3 4 5])
;; => {:first 1 :second 2 :rest (3 4 5)}
```
### 1.3 Аргументи от тип ключова дума
Clojure поддържа аргументи от тип ключова дума чрез деструктуриране:
```clojure
(defn configure [name & {:keys [debug verbose output]
:or {debug false verbose false output "stdout"}}]
{:name name :debug debug :verbose verbose :output output})
(configure "test" :debug true :verbose true :output "file.txt")
;; => {:name "test" :debug true :verbose true :output "file.txt"}
```
### 1.4 Взаимна рекурсия
Функциите могат да се извикват една друга:
```clojure
(defn even? [n]
(if (zero? n)
true
(odd? (dec n))))
(defn odd? [n]
(if (zero? n)
false
(even? (dec n))))
(even? 4) ;; => true
(odd? 3) ;; => true
```
### 1.5 Мемоизация
Кеширане на резултати от функции:
```clojure
(defn slow-fib [n]
(if (<= n 1)
n
(+ (slow-fib (- n 1))
(slow-fib (- n 2)))))
(def memo-fib (memoize slow-fib))
;; Разликата във времето е драматична за по-големи n
(time (memo-fib 35)) ;; Много по-бързо
```
### 1.6 Пред- и пост-условия
Валидиране на входове и изходи:
```clojure
(defn absolute-value [n]
{:pre [(number? n)]
:post [(number? %)
(>= % 0)]}
(if (neg? n)
(- n)
n))
(defn divide [a b]
{:pre [(not (zero? b)) "Делителят не може да е нула"]}
(/ a b))
```
### 1.7 Метаданни на функции
Функциите могат да имат метаданни:
```clojure
(defn ^:private internal-helper [x]
x)
(defn ^:deprecated old-function [x]
x)
;; Проверете метаданните
(meta #'internal-helper)
;; => {:private true, ...}
```
### 1.8 Арности и претоварване
```clojure
(defn arity-error []
(throw (ex-info "Невалидна арност" {})))
(defn complete
([x] (complete x 1))
([x y] (+ x y))
([x y z] (+ x y z)))
```
---
## 2. Мързеливи серии - задълбочено
### 2.1 Реализиране на серии
Мързеливите серии се реализират (оценяват) при необходимост:
```clojure
(def lazy-nats (range)) ;; Безкрайни
(take 10 lazy-nats) ;; Реализира първите 10
;; Принудете пълна реализация
(doall lazy-nats) ;; Опасно: безкрайна!
(doall (take 1000 lazy-nats))
```
### 2.2 Chunked серии
Мързеливите серии на Clojure са chunked (типично 32 елемента):
```clojure
;; Range създава chunked серии
(class (range 100)) ;; => clojure.lang.LongRange
;; Всеки chunk се реализира наведнъж
```
### 2.3 Lazy Cons и реализация
```clojure
;; cons създава мързелива серия
(def custom-seq (cons 1 (lazy-seq (cons 2 ()))))
;; lazy-seq отлага изчисленията
(defn fibs []
(cons 0
(cons 1
(map + (fibs) (rest (fibs))))))
```
### 2.4 Seqable обекти
Всеки обект може да бъде направен последователен чрез имплементиране на `seq`:
```clojure
(extend-type String
clojure.core.protocols/Coll
(coll [s] (seq s)))
;; Сега низовете работят със серийни функции
(map clojure.string/upper-case "hello")
;; => (\H \E \L \L \O)
```
### 2.5 Безкрайни серии
```clojure
;; Повтарящ се цикъл
(def repeating (cycle [:a :b :c]))
;; Повтаряне завинаги
(def ones (repeatedly 1))
(def randoms (repeatedly #(rand-int 100)))
;; Iterate - прилага функция към предишния резултат
(def powers-of-two (iterate #(* 2 %) 1))
(def collatz (iterate #(if (even? %) (/ % 2) (inc (* 3 %))) 1))
```
### 2.6 Производителност на сериите
```clojure
;; Не дръжте head на мързелива серия
(defn bad-sum []
(let [large-seq (range 10000000)]
(reduce + (take 10 large-seq)))) ;; Държи референция към цялата серия
(defn good-sum []
(reduce + (take 10 (range 10000000)))) ;; Head може да бъде GC'd
```
### 2.7 Eager vs Lazy
```clojure
;; mapcat може да бъде eager
(mapcat reverse [[1 2] [3 4]]) ;; => (2 1 4 3)
;; into принуждава реализация
(into [] (map inc (range 1000)))
;; into е ефективен - не създава междинни колекции
```
---
## 3. Трансдюсъри
Трансдюсърите са съставни, мързеливи трансформации, независими от входния контекст.
### 3.1 Създаване на трансдюсъри
```clojure
;; Без контекст
(def increment (map inc))
(def only-evens (filter even?))
;; Съставяне на трансдюсъри
(def transform (comp
(filter even?)
(map inc)
(take 10)))
```
### 3.2 Използване на трансдюсъри
```clojure
;; С всякаква последователна колекция
(transduce transform + (range 100))
;; => Сума на първите 10 четни числа + 1
(into [] transform (range 100))
;; => [3 5 7 9 11 13 15 17 19 21]
(sequence transform (range 100))
;; => Връща мързелива серия
```
### 3.3 Завършващи редукции
Някои трансдюсъри трябва да направят нещо в края:
```clojure
(def taking-transform
(fn [rf]
(let [n (volatile! 5)]
(fn
([] (rf))
([result] (rf result))
([result input]
(if (pos? @n)
(do (vswap! n dec)
(rf result input))
(reduced result)))))))
(transduce taking-transform + (range 100)) ;; => 10
```
### 3.4 Ранно прекратяване
```clojure
;; reduced увива стойност за спиране рано
(transduce (filter odd?) + (range 10))
;; => 25 (1+3+5+7+9)
;; Използвайте reduced? за проверка
(reduced? (reduced 5)) ;; => true
```
### 3.5 Cat и завършване
```clojure
(require '[clojure.core.protocols :as p])
;; Завършващата арност на редуциращата функция
(transduce
(map inc)
(fn
([result] result) ;; завършваща арност
([result input] (rf result input)))
[]
(range 5))
```
---
## 4. Specs и валидация
### 4.1 Въведение в Spec
Spec предоставя валидация по време на изпълнение и генеративно тестване (чрез `clojure.spec.gen`).
### 4.2 Дефиниране на Specs
```clojure
(require '[clojure.spec.alpha :as s])
(s/def ::name string?)
(s/def ::age (s/and int? #(>= % 0)))
(s/def ::person (s/keys :req [::name ::age]))
```
### 4.3 Конформиране
```clojure
(s/conform ::age 25) ;; => 25
(s/conform ::age -5) ;; => :clojure.spec.alpha/invalid
(s/conform ::person {::name "John" ::age 30})
;; => {::name "John" ::age 30}
```
### 4.4 Валидация с `valid?`
```clojure
(s/valid? ::age 25) ;; => true
(s/valid? ::age -5) ;; => false
(s/valid? ::person {::name "John" ::age 30}) ;; => true
```
### 4.5 Генеративно тестване
```clojure
(require '[clojure.spec.gen.alpha :as gen])
;; Генериране на стойности
(gen/generate (s/gen ::age))
(gen/sample (s/gen ::age))
;; Тестване със spec
(s/def ::email (s/and string?
#(re-find #"@" %)))
(s/fdef greet
:args (s/cat :name ::name)
:ret string?)
;; Пускане на генеративни тестове
(stest/instrument `greet)
```
### 4.6 Multi-spec
```clojure
(s/def ::shape (s/multi-spec :type keyword?))
(defmethod shape-spec :circle [_]
(s/keys :req [:radius]))
(defmethod shape-spec :rect [_]
(s/keys :req [:width :height]))
```
---
## 5. Протоколът Collection
### 5.1 Йерархия на колекциите
```
IPersistentCollection
IPersistentList
IPersistentVector
IPersistentMap
IPersistentSet
```
### 5.2 Ключови протоколи
```clojure
;; Sequential
(first coll)
(rest coll)
(next coll)
(cons item coll)
;; Counted
(count coll)
;; Indexed (Vectors)
(nth coll index)
(get coll index)
;; Associative (Maps)
(assoc coll key val)
(dissoc coll key)
(find coll key)
(keys coll)
(vals coll)
```
### 5.3 Разширяване на колекции
```clojure
;; Използване на reify
(def my-collection
(reify
clojure.core.protocols/Coll
(coll [this] this)
clojure.core.protocols/Indexed
(nth [this i] (get [10 20 30] i))))
(nth my-collection 1) ;; => 20
```
### 5.4 Персонализирани Reducibles
```clojure
(defrecord Range [start end]
clojure.core.protocols/Coll
(coll [this] (seq (range start end)))
(reduce + (Range. 1 10)) ;; => 45
```
---
## 6. Reducibles
Reduciers предоставят начин за извършване на паралелни редукции без мързеливи серии.
### 6.1 Използване на Reducers
```clojure
(require '[clojure.core.reducers :as r])
;; Паралелна map (автоматично паралелизира в fold)
(r/map inc (range 1000))
;; fold използва паралелна редукция
(r/fold + (r/map inc (range 1000000)))
```
### 6.2 Персонализирани Reducers
```clojure
;; fold изисква foldable колекция и комбинираща функция
(r/fold
(fn ([] 0) ([x y] (+ x y)))
(fn ([x] x) ([x y] (+ x y)))
(range 1000))
```
---
## 7. Паралелизъм
### 7.1 pmap
Паралелна map (мързелива):
```clojure
;; Като map, но се изпълнява паралелно
(time
(doall (pmap #(do (Thread/sleep 100) %) (range 10))))
;; Много по-бързо от обикновена map със задръстващи операции
```
### 7.2 Reducers за паралелизъм
```clojure
;; Сгъване с множество ядра
(r/fold 100 + (range 10000000))
;; Персонализирана комбинираща функция
(r/fold
100
(fn ([] 0) ([a b] (+ a b)))
(fn ([] 0) ([a b] (+ a b)))
(range 10000000))
```
### 7.3 Futures
```clojure
;; Независими паралелни задачи
(let [a (future (compute-a))
b (future (compute-b))]
[@a @b]) ;; Изчаква и двете
```
### 7.4 CompletableFuture (само бележка)
Забележка: Java's `CompletableFuture` изисква Java interop. Чисти алтернативи на Clojure включват:
- Core.async канали
- Manifold библиотека
- Promises с futures
---
## 8. Оптимизация на производителността
### 8.1 Persistent структури от данни
Persistent структурите от данни на Clojure споделят структура:
```clojure
;; Добавяне към вектор споделя повечето структура
(def v1 [1 2 3 4 5])
(def v2 (conj v1 6))
;; v1 и v2 споделят [1 2 3 4 5]
;; Само нови възли се създават за пътя към новия елемент
```
### 8.2 Transient структури от данни
За локални, временни мутации:
```clojure
(defn slow-accumulation []
(loop [coll []
i 0]
(if (= i 100000)
coll
(recur (conj coll i) (inc i)))))
(defn fast-accumulation []
(persistent!
(loop [coll (transient [])
i 0]
(if (= i 100000)
coll
(recur (conj! coll i) (inc i))))))
(time (count (slow-accumulation))) ;; По-бавно
(time (count (fast-accumulation))) ;; По-бързо
```
### 8.3 Chunked операции
```clojure
;; Предпочитайте chunked операции
(into [] (map inc (range 1000))) ;; Създава една междинна серия
(into [] (mapcat list (range 100))) ;; Изравнява мързеливо
```
### 8.4 Поддържане на аргументи eager
```clojure
;; Лошо: дръж head на серията
(def bad-result (map f large-collection))
;; Добро: обработвайте незабавно
(into [] (map f large-collection))
```
### 8.5 Batch обработка
```clojure
;; Вместо много малки операции
(doseq [x items]
(update-db x))
;; Помислете за batch-ване
(batch-update items)
```
### 8.6 Предварително зареждане и кеширане
```clojure
;; Мемоизация за скъпи изчисления
(def cached-expensive-lookup
(memoize (fn [k]
(compute-expensively k))))
;; Предварително зареждане при стартиране
(def initialized-data
(delay (load-and-process-data)))
```
### 8.7 Бенчмаркинг
```clojure
(require '[criterium.core :as c])
(c/quick-bench (reduce + (range 10000)))
;; Докладва mean, std deviation и т.н.
```
---
## 9. Индекс
### A
- `arity` - [1.8](#18-арности-и-претоварване)
- `assert` - [1.6](#16-пред--и-пост-условия)
### C
- `chunked-seq?` - [2.2](#22-chunked-серии)
- `coll` - [5.3](#53-разширяване-на-колекции)
- `complement` - [1.3](#13-аргументи-от-тип-ключова-дума)
- `comp` - [1.3](#13-аргументи-от-тип-ключова-дума)
### D
- `delay` - [2.6](#26-производителност-на-сериите)
- `delayed?` - [2.6](#26-производителност-на-сериите)
- `deref` - [2.6](#26-производителност-на-сериите)
### F
- `force` - [2.6](#26-производителност-на-сериите)
- `fnil` - [1.3](#13-аргументи-от-тип-ключова-дума)
- `fold` - [6.2](#62-използване-на-reducers)
- `fpartial` - [1.3](#13-аргументи-от-тип-ключова-дума)
### G
- `gen` - [4.5](#45-генеративно-тестване)
- `generate` - [4.5](#45-генеративно-тестване)
### I
- `into` - [3.2](#32-използване-на-трансдюсъри)
- `iterate` - [2.5](#25-безкрайни-серии)
### L
- `lazy-cat` - [2.3](#23-lazy-cons-и-реализация)
- `lazy-seq` - [2.3](#23-lazy-cons-и-реализация)
- `let` - [1.2](#12-rest-параметри-в-детайли)
### M
- `memoize` - [1.5](#15-мемоизация)
- `multi-spec` - [4.6](#46-multi-spec)
- `mmerge` - [6.1](#61-използване-на-reducers)
### N
- `nested` - [5.3](#53-разширяване-на-колекции)
- `next` - [5.2](#52-ключови-протоколи)
### P
- `parallelize` - [7.2](#72-reducers-за-паралелизъм)
- `partial` - [1.3](#13-аргументи-от-тип-ключова-дума)
- `pmap` - [7.1](#71-pmap)
- `promote` - [6.2](#62-използване-на-reducers)
### R
- `realized?` - [2.1](#21-реализиране-на-серии)
- `reduced` - [3.4](#34-ранно-прекратяване)
- `reduced?` - [3.4](#34-ранно-прекратяване)
- `reductions` - [3.3](#33-завършващи-редукции)
### S
- `sample` - [4.5](#45-генеративно-тестване)
- `sequence` - [3.2](#32-използване-на-трансдюсъри)
- `spec` - [4.1](#41-въведение-в-spec)
- `split-with` - [2.6](#26-производителност-на-сериите)
### T
- `test` - [4.5](#45-генеративно-тестване)
- `transduce` - [3.2](#32-използване-на-трансдюсъри)
- `transient` - [8.2](#82-transient-структури-от-данни)
- `tree-seq` - [2.6](#26-производителност-на-сериите)
### V
- `volatile!` - [1.7](#17-метаданни-на-функции)
- `volatile?` - [1.7](#17-метаданни-на-функции)
---
*Чист Clojure: Разширени теми*
+629
View File
@@ -0,0 +1,629 @@
# Чист Clojure: Структура на проекта и инструменти
## Съдържание
1. [Структура на проекта](#1-структура-на-проекта)
2. [deps.edn и CLI инструменти](#2-depsedn-и-cli-инструменти)
3. [Инфраструктура за тестване](#3-инфраструктура-за-тестване)
4. [Работен процес за разработка](#4-работен-процес-за-разработка)
5. [Инструменти за качество на кода](#5-инструменти-за-качество-на-кода)
6. [Изграждане и деплойване](#6-изграждане-и-деплойване)
7. [Екосистема от библиотеки](#7-екосистема-от-библиотеки)
8. [Техники за дебъгване](#8-техники-за-дебъгване)
9. [Индекс](#9-индекс)
---
## 1. Структура на проекта
### 1.1 Типична структура на проект
```
myproject/
├── deps.edn
├── src/
│ └── myproject/
│ ├── core.clj
│ ├── util.clj
│ └── spec/
│ └── core_spec.clj
├── test/
│ └── myproject/
│ ├── core_test.clj
│ └── util_test.clj
├── resources/
├── doc/
│ └── intro.md
└── README.md
```
### 1.2 Namespace като файлови пътища
Namespaces се мапват към файлови пътища:
```clojure
;; src/myproject/core.clj
(ns myproject.core)
;; src/myproject/util.clj
(ns myproject.util)
;; src/myproject/spec/user.clj
(ns myproject.spec.user)
```
### 1.3 Multi-module проекти
```clojure
;; deps.edn с множество модули
{:paths ["src" "modules/common/src"]
:deps {org.clojure/clojure {:mvn/version "1.11.1"}}
:aliases
{:dev {:extra-paths ["test"]
:extra-deps {}}}}
```
### 1.4 Разделяне на Source и Test
- Source код: директория `src/`
- Тестове: директория `test/`
- И двете се добавят към classpath по време на разработка
---
## 2. deps.edn и CLI инструменти
### 2.1 Референция на deps.edn
```clojure
{:deps {org.clojure/clojure {:mvn/version "1.11.1"}
org.clojure/data.json {:mvn/version "2.4.0"}
clojure.java-time/clojure.java-time {:mvn/version "1.4.2"}
}
:paths {:src ["src"]
:test ["test"]}
:aliases
{:test {:extra-paths ["test"]
:extra-deps {org.clojure/test.check {:mvn/version "1.1.1"}}}
:dev {:jvm-opts ["-Xmx4g"]}
:bench {:extra-deps {criterium/criterium {:mvn/version "0.4.4"}}}}
```
### 2.2 Пускане на код
```bash
# Пускане на скрипт
clj -M script.clj
# Пускане с test alias
clj -M:test -m myproject.test-runner
# Пускане на REPL с deps
clj -M
# Пускане с конкретни deps
clj -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.11.1"}}}'
```
### 2.3 Разбиране на aliases
Aliases модифицират classpath или поведение:
```bash
# Тест с generative проверка
clj -M:test:gen
# Production build
clj -M:prod build
# Dev mode с допълнителни проверки
clj -M:dev
```
### 2.4 Създаване на зависимости
```clojure
;; deps.edn
{:deps {io.github.clojure/data.json {:git/sha "..."}}}
;; Classpath
clj -Sdescribe # Покажи ефективния classpath
```
---
## 3. Инфраструктура за тестване
### 3.1 test.check за генеративно тестване
```clojure
(require '[clojure.test.check :as tc]
'[clojure.test.check.generators :as gen]
'[clojure.test.check.properties :as prop])
(def prop-sort-idempotent
(prop/for-all
[v (gen/vector gen/int)]
(= (sort v) (sort (sort v)))))
(tc/quick-check 100 prop-sort-idempotent)
;; => {:result true, :pass? true, ...}
```
### 3.2 Fixtures за setup/teardown
```clojure
(ns myproject.test-util
(:require [clojure.test :as t]
[myproject.db :as db]))
(defn with-test-db [f]
(db/connect! :test)
(f)
(db/disconnect!))
(defn with-logging [f]
(println "Преди тест")
(f)
(println "След тест"))
;; Прилагане на fixtures
(t/use-fixtures :each with-test-db with-logging)
(t/use-fixtures :once db/setup-once)
```
### 3.3 Тестови namespace-и
```clojure
(ns myproject.core-test
(:require [clojure.test :as t]
[myproject.core :as core]))
(t/deftest ^:integration api-test
"Интеграционни тестове за външно API"
...)
;; Пускане на конкретни тестове
(t/run-tests 'myproject.core-test)
(t/run-tests #"myproject.*test")
```
### 3.4 Expectations-style тестване
```clojure
;; Използване на expectations библиотека
(require '[expectations :refer [expect]])
(expect 4 (+ 2 2))
(expect ArithmeticException (/ 1 0))
(expect [:a :b :c] (filterv odd? [1 2 3 4]))
```
### 3.5 Midje (за четимост)
```clojure
(require '[midje.sweet :refer [fact facts =>]])
(fact "събирането работи"
(+ 2 2) => 4)
(facts "за низовете"
(fact "upper-case работи"
(clojure.string/upper-case "hello") => "HELLO"))
```
---
## 4. Работен процес за разработка
### 4.1 REPL-driven разработка
```clojure
;; Стартиране на REPL
user=> (require '[myproject.core :as core] :reload)
;; Редактиране на код, презареждане
user=> (require '[myproject.core :as core] :reload :verbose)
;; Презареждане на всички променени namespaces
user=> (require '[clojure.tools.namespace.repl :as ns]
:refer [refresh refresh-all])
user=> (refresh)
```
### 4.2 Hot Loading на код
```clojure
;; В REPL
(def server (atom nil))
(defn start-server []
(swap! server assoc :running true))
;; След редактиране на core, просто презаредете
(require '[myproject.core :as core] :reload)
```
### 4.3 Проследяване на source
```clojure
;; Проследяване на променени файлове
(require '[clojure.java.io :as io]
'[clojure.tools.namespace.track :as track])
(defn track-changes []
(let [tracker (atom (track/tracker))]
(fn []
(swap! tracker track/step)
(track/deps @tracker))))
```
### 4.4 Богати comment блокове
```clojure
(defn process-data [input]
{:pre [(sequential? input)]}
(mapv inc input))
(comment
;; Експерименти по време на разработка
(process-data [1 2 3])
;; Тестване на гранични случаи
(process-data [])
;; Интерактивно дебъгване
(def test-data (load-data))
)
```
---
## 5. Инструменти за качество на кода
### 5.1 eastwood (Linter)
```clojure
;; deps.edn alias
:lint {:extra-deps {lancem待/clojure-eastwood {:mvn/version "..."}}}
;; Пускане
clj -M:lint -m eastwood.lint
```
### 5.2 clj-kondo (Бърз Linter)
```bash
# Инсталиране
brew install clj-kondo
# Пускане върху проект
clj-kondo --lint src/
```
### 5.3 Форматиране с cljfmt
```clojure
;; deps.edn
:format {:extra-deps {com.github.cljfmt/cljfmt {:mvn/version "..."}}}
# Проверка
clj -M:format check src/
# Поправка
clj -M:format fix src/
```
### 5.4 Typed Clojure (Незадължително проверяване на типове)
```clojure
(require '[clojure.core.typed :as t])
(t/ann my-function [t/Int -> t/Int])
(defn my-function [x]
(inc x))
;; Проверка на типовете
(t/check-ns)
```
---
## 6. Изграждане и деплойване
### 6.1 Изграждане на Uberjars
```clojure
;; tools.build
(require '[clojure.tools.build.api :as b])
(def lib 'com.mycompany/myapp)
(def version "1.0.0")
(def target-dir "target")
(defn uberjar [opts]
(b/java-command
{:basis (:basis opts)
:main 'myproject.core
:jar-file (b/path target-dir "myapp.jar")
:uber-jar true}))
```
### 6.2 Native Image с GraalVM
```bash
# Компилиране на Clojure до JVM bytecode първо
clojure -M:build compile
# Изграждане на native image
native-image --initialize-at-build-time=clojure.lang.RT \
-jar myapp.jar
```
### 6.3 Docker интеграция
```dockerfile
FROM clojure:openjdk-17-lein
WORKDIR /app
COPY deps.edn .
RUN clj -M -P
COPY src src
COPY test test
ENVlein uberjar
ENTRYPOINT ["java", "-jar", "target/myapp.jar"]
```
### 6.4 CI/CD Pipeline
```yaml
# GitHub Actions пример
name: Clojure CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: DeLaGuardo/setup-clojure@10
with:
backend: 'cli'
version: '1.11.1'
- run: clj -M:test
- run: clj -M:lint
```
---
## 7. Екосистема от библиотеки
### 7.1 Web разработка
```clojure
;; HTTP Сървър - Ring (чист Clojure)
{:deps {ring/ring {:mvn/version "1.9.5"}}
;; Routes - Compojure
{:deps {compojure/compojure {:mvn/version "1.6.2"}}}
```
### 7.2 Обработка на данни
```clojure
;; Манипулация на данни
{:deps {zipkin/zikaron {:mvn/version "1.0.0"}}}
;; CSV handling
{:deps {org.clojure/data.csv {:mvn/version "1.0.1"}}
;; JSON (чист Clojure)
{:deps {org.clojure/data.json {:mvn/version "2.4.0"}}}
```
### 7.3 Асинхронно програмиране
```clojure
;; Core async е вграден
;; Няма допълнителни зависимости за канали
;; За допълнителни async модели
{:deps {manifold/manifold {:mvn/version "0.4.0"}}}
```
### 7.4 Достъп до бази данни
```clojure
;; Чист Clojure JDBC wrapper
{:deps {org.clojure/java.jdbc {:mvn/version "0.7.12"}}
;; SQL DSL
{:deps {sqlkorma/sqlkorma {:mvn/version "0.4.0"}}}
```
### 7.5 Библиотеки за тестване
```clojure
{:deps {expectations/expectations {:mvn/version "2.0.0"}}
{midje/midje {:mvn/version "1.9.10"}}
{org.clojure/test.check {:mvn/version "1.1.1"}}}
```
### 7.6 Намиране на библиотеки
- Clojars.org - Общностно хранилище
- Clojuredocs.org - Документация с примери
- Awesome-clojure - Куриран списък
---
## 8. Техники за дебъгване
### 8.1 Print дебъгване
```clojure
;; Прости отпечатвания
(println "Debug:" variable)
;; С pretty printer
(require '[clojure.pprint :as pp])
(pp/pprint data-structure)
;; Tap за дебъгване
(tap> {:event :processing :data x})
```
### 8.2 Stack traces
```clojure
;; Вземете пълен stack trace
(.printStackTrace *e)
;; Ex-data за spec грешки
(try
(s/conform ::spec value)
(catch Exception e
(ex-data e)))
```
### 8.3 REPL дебъгване
```clojure
;; Инспектиране на стойности
user> (def data (s/gen ::my-spec))
user> data
;; Стъпка по стъпка с trace
(trace (reduce + (range 10)))
```
### 8.4 Watching state
```clojure
;; Watch atoms
(add-watch my-atom :debug
(fn [k r o n]
(println "Променено:" o "->" n)))
;; Watch refs в транзакция
(dosync
(trace (alter my-ref f)))
```
### 8.5 Breakpoints
```clojure
;; Използване на dbg macro (от tools.trace)
(require '[clojure.tools.trace :as t])
(t/dbg expression)
```
### 8.6 Logging
```clojure
(require '[clojure.tools.logging :as log])
(log/info "Приложението стартира")
(log/debug "Обработка" :item item)
(log/error e "Неуспех при обработка")
```
---
## 9. Индекс
### A
- `add-watch` - [8.4](#84-watching-state)
- `alias` - [1.2](#12-референция-на-depsedn)
### B
- `build` - [6.1](#61-изграждане-на-uberjars)
### C
- `check-ns` - [5.4](#54-typed-clojure-незадължително-проверяване-на-типове)
- `clojure.tools.namespace` - [4.1](#41-repl-driven-разработка)
- `comment` - [4.4](#44-богати-comment-блокове)
### D
- `dbg` - [8.5](#85-breakpoints)
- `deps.edn` - [2.1](#21-референция-на-depsedn)
### E
- `eastwood` - [5.1](#51-eastwood-linter)
### F
- `find-libs` - [7.6](#76-намиране-на-библиотеки)
### G
- `gen` - [3.1](#31-testcheck-за-генеративно-тестване)
### I
- `instrument` - [3.1](#31-testcheck-за-генеративно-тестване)
### L
- `lein` - [6.3](#63-docker-интеграция)
- `load-file` - [4.2](#42-hot-loading-на-код)
### M
- `memoize` - [4.3](#43-проследяване-на-source)
- `merge` - [8.2](#82-stack-traces)
### N
- `ns-publics` - [4.1](#41-repl-driven-разработка)
### P
- `pp/pprint` - [8.1](#81-print-дебъгване)
- `profile` - [8.3](#83-repl-дебъгване)
### Q
- `quick-check` - [3.1](#31-testcheck-за-генеративно-тестване)
### R
- `reduce` - [8.3](#83-repl-дебъгване)
- `refresh` - [4.1](#41-repl-driven-разработка)
- `reload` - [4.1](#41-repl-driven-разработка)
- `run-tests` - [3.3](#33-тестови-namespace-и)
### S
- `s/conform` - [8.2](#82-stack-traces)
- `s/gen` - [3.1](#31-testcheck-за-генеративно-тестване)
- `shadow` - [6.2](#62-native-image-с-graalvm)
- `spec` - [8.2](#82-stack-traces)
### T
- `tap>` - [8.1](#81-print-дебъгване)
- `test` - [3.3](#33-тестови-namespace-и)
- `trace` - [8.5](#85-breakpoints)
- `track` - [4.3](#43-проследяване-на-source)
### U
- `uberjar` - [6.1](#61-изграждане-на-uberjars)
- `use-fixtures` - [3.2](#32-fixtures-за-setupteardown)
### V
- `verify` - [3.1](#31-testcheck-за-генеративно-тестване)
---
*Чист Clojure: Структура на проекта и инструменти*
+693
View File
@@ -0,0 +1,693 @@
# Чист Clojure: Практически рецепти
## Съдържание
1. [Често срещани модели](#1-често-срещани-модели)
2. [Рецепти за трансформация на данни](#2-рецепти-за-трансформация-на-данни)
3. [Рецепти за управление на състояние](#3-рецепти-за-управление-на-състояние)
4. [Async рецепти](#4-async-рецепти)
5. [Рецепти за валидация](#5-рецепти-за-валидация)
6. [Модели за дизайн на API](#6-модели-за-дизайн-на-api)
7. [Рецепти за тестване](#7-рецепти-за-тестване)
8. [Рецепти за производителност](#8-рецепти-за-производителност)
---
## 1. Често срещани модели
### 1.1 Maybe/Option модел
```clojure
(defn safe-divide [a b]
(if (zero? b)
nil
(/ a b)))
(defn map-safe [f coll]
(sequence (comp (filter some?)
(map f))
coll))
(map-safe #(safe-divide 10 %) [2 0 4 0 5])
;; => (5 2 2)
```
### 1.2 Either/Result модел
```clojure
(defn parse-int [s]
(try
{:success (Long/parseLong s)}
(catch NumberFormatException _
{:error "Невалидно число"})))
(defn bind [result f]
(if (:error result)
result
(f (:success result))))
(-> (parse-int "42")
(bind #(* % 2))
(bind #(+ % 1)))
;; => {:success 85}
```
### 1.3 Модел State Machine
```clojure
(defprotocol StateMachine
(transition [state event])
(current-state [state]))
(defrecord TrafficLight [state]
StateMachine
(transition [_ event]
(case [state event]
[:green :timeout] (->TrafficLight :yellow)
[:yellow :timeout] (->TrafficLight :red)
[:red :timeout] (->TrafficLight :green)
_))
(current-state [_] state))
```
### 1.4 Builder модел
```clojure
(defn make-builder [defaults]
(let [state (atom defaults)]
(reify
Object
(toString [_] (str @state))
clojure.core.protocols/Coll
(coll [_] (seq @state))
clojure.lang.IFn
(invoke [_ k v]
(swap! state assoc k v)
this)
(invoke [_ m]
(swap! state merge m)
this))))
(def builder (make-builder {:debug false :timeout 5000}))
(-> builder
(assoc :host "localhost")
(merge {:port 8080})
str)
```
---
## 2. Рецепти за трансформация на данни
### 2.1 Вложен достъп до данни
```clojure
(defn get-in-safe [m keys default]
(try
(get-in m keys)
(catch NullPointerException _
default)))
;; Със spec валидация
(get-in-safe {:user {:address {:city "Sofia"}}}
[:user :address :city]
"Неизвестно")
;; Дълбоко обновление
(defn update-in-safe [m keys f & args]
(if (get-in m keys)
(apply update-in m keys f args)
m))
```
### 2.2 Групиране и агрегиране
```clojure
;; Групиране по множество ключове
(defn group-by-multiple [ks coll]
(reduce
(fn [acc item]
(update-in acc (map item ks) conj item))
{}
coll))
(group-by-multiple [:department :role]
[{:name "Alice" :department "Eng" :role "Dev"}
{:name "Bob" :department "Eng" :role "Dev"}
{:name "Carol" :department "Sales" :role "Mgr"}])
;; Rolling агрегации
(defn rolling [f n coll]
(let [window (vec (take n coll))]
(lazy-seq
(cons (f window)
(rolling f n (rest coll))))))
```
### 2.3 Pivot Tables
```clojure
(defn pivot-table [data row-key col-key value-fn]
(reduce
(fn [table row]
(let [r (row-key row)
c (col-key row)
v (value-fn row)]
(assoc-in table [r c] v)))
{}
data))
(pivot-table [{:month "Jan" :region "East" :sales 100}
{:month "Jan" :region "West" :sales 150}
{:month "Feb" :region "East" :sales 200}]
:month :region :sales)
;; => {"Jan" {"East" 100 "West" 150}
"Feb" {"East" 200}}
```
### 2.4 Операции с дървета
```clojure
;; Сума на всички числови листа
(defn tree-sum [tree]
(reduce + 0
(tree-seq sequential? seq tree)))
;; Map върху дърво
(defn tree-map [f tree]
(postwalk #(if (sequential? %) (mapv f %) %) tree))
;; Намиране в дърво
(defn tree-find [pred tree]
(first (filter pred (tree-seq sequential? seq tree))))
```
---
## 3. Рецепти за управление на състояние
### 3.1 Service модел с Atoms
```clojure
(defprotocol Service
(start [this])
(stop [this])
(process [this input]))
(defn make-service [config]
(let [state (atom {:config config
:running false
:cache {}})]
(reify
Service
(start [_]
(swap! state assoc :running true))
(stop [_]
(swap! state assoc :running false))
(process [_ input]
(when-not (:running @state)
(throw (ex-info "Service не е стартиран" {})))
(if-let [cached (get-in @state [:cache input])]
cached
(let [result (compute input)]
(swap! state assoc-in [:cache input] result)
result))))))
```
### 3.2 Event Sourcing
```clojure
(defn make-event-store []
(let [events (atom [])
snapshots (atom {})]
(reify
Object
(toString [_] (pr-str @events))
clojure.core.protocols/Coll
(coll [_] (seq @events))
clojure.lang.IFn
(invoke [_ event]
(let [new-state (apply-event @snapshots event)]
(swap! events conj event)
(when (seq? new-state)
(reset! snapshots new-state))))
(invoke [_ n]
(get @snapshots n)))))
(defn apply-event [state event]
(case (:type event)
:created (assoc state (:id event) (:data event))
:updated (update state (:id event) merge (:data event))
:deleted (dissoc state (:id event))
state))
```
### 3.3 Cooldown механизъм
```clojure
(defn make-cooldown [timeout-ms]
(let [last-call (atom 0)]
(fn []
(let [now (System/currentTimeMillis)]
(when (> (- now @last-call) timeout-ms)
(reset! last-call now)
true)))))
(def rate-limiter (make-cooldown 1000))
;; Употреба
(when (rate-limiter)
(do-something))
```
### 3.4 Circuit Breaker
```clojure
(defn make-circuit-breaker [failure-threshold reset-timeout]
(let [state (atom {:status :closed
:failures 0
:last-failure 0})]
(fn [f]
(let [current @state]
(case (:status current)
:open
(if (> (- (System/currentTimeMillis) (:last-failure current))
reset-timeout)
(do (swap! state assoc :status :half-open)
(try
(let [result (f)]
(swap! state assoc :status :closed :failures 0)
result)
(catch Exception e
(swap! state assoc :status :open :last-failure (System/currentTimeMillis))
(throw e))))
(throw (ex-info "Circuit open" {})))
:half-open
(try
(let [result (f)]
(swap! state assoc :status :closed :failures 0)
result)
(catch Exception e
(swap! state assoc :status :open :last-failure (System/currentTimeMillis)
)
(throw e)))
:closed
(try
(let [result (f)]
(swap! state assoc :failures 0)
result)
(catch Exception e
(let [failures (inc (:failures current))]
(swap! state assoc :failures failures
:last-failure (System/currentTimeMillis))
(when (>= failures failure-threshold)
(swap! state assoc :status :open))
(throw e)))))))))
```
---
## 4. Async рецепти
### 4.1 Channel Pipeline
```clojure
(defn channel-pipeline [in-f out-f & channels]
(doseq [ch channels]
(async/go
(loop []
(when-let [value (<! ch)]
(out-f value)
(recur))))))
;; Употреба
(let [input-chan (async/chan 100)
process-chan (async/chan 100)
output-chan (async/chan 100)]
(async/pipeline 10 process-chan (map process-item) input-chan)
(async/pipeline 10 output-chan (map format-output) process-chan))
```
### 4.2 Multiplexing канали
```clojure
(defn multiplex [in-chan & out-chans]
(async/go
(loop [value (<! in-chan)]
(when-not (nil? value)
(doseq [ch out-chans]
(>! ch value))
(recur (<! in-chan))))))
;; Употреба
(let [input (async/chan)
out1 (async/chan)
out2 (async/chan)]
(multiplex input out1 out2)
;; Сега input се broadcast-ва към двата изхода
)
```
### 4.3 Timeout модели
```clojure
;; Timeout на операция
(async/go
(let [result (async/alts!! [work-chan
(async/timeout 5000)])]
(if (= result :timed-out)
{:status :timeout}
{:status :success :value (first result)})))
;; Retry с exponential backoff
(defn with-retry [f max-attempts delay-ms]
(async/go
(loop [attempts 0]
(let [result (async/<! (async/timeout delay-ms))]
(if (= :failure result)
(if (< attempts max-attempts)
(recur (inc attempts))
{:status :failed})
{:status :success :value result})))))
```
### 4.4 Windowing
```clojure
(defn windowed [in size overlap]
(let [out (async/chan)]
(async/go
(loop [window (vec (take size (async/<! in)))]
(when (seq window)
(>! out window)
(let [next-items (vec (take overlap (rest window)))
remaining (- size overlap)
new-items (vec (take remaining (async/<! in)))]
(recur (into next-items new-items))))))
out))
```
---
## 5. Рецепти за валидация
### 5.1 Многоетапна валидация
```clojure
(defn validate-stages [data & validators]
(reduce
(fn [result validator]
(let [errors (validator result)]
(if (seq errors)
(reduced {:status :error :errors errors})
result)))
{:status :ok :data data}
validators))
(defn non-blank [field]
(fn [result]
(when (clojure.string/blank? (get-in result [:data field]))
[field "не може да е празно"])))
(defn max-length [field length]
(fn [result]
(when (> (count (get-in result [:data field])) length)
[field (str "трябва да е най-много" length "символа")])))
(validate-stages
{:name ""}
(non-blank :name)
(max-length :name 50))
;; => {:status :error :errors [:name "не може да е празно"]}
```
### 5.2 Schema валидация
```clojure
(def email-regex #"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$")
(defn validate-email [email]
(when-not (re-find email-regex email)
"Невалиден email формат"))
(defn validate-user [user]
(reduce-kv
(fn [errors field validate]
(if-let [error (validate (get user field))]
(conj errors [field error])
errors))
[]
{:name [#(when (clojure.string/blank? %) "Името е задължително")]
:email [validate-email
#(when (> (count %) 100) "Email е твърде дълъг")]
:age [#(when (or (nil? %) (neg? %)) "Възрастта трябва да е положителна")]}))
(validate-user {:name "John" :email "john@example.com" :age 30})
;; => []
```
### 5.3 Contract тестване
```clojure
(defmacro defcontract [name input-spec output-spec & body]
`(defn ~name [& args#]
(let [input# (first args#)
output# (apply ~(into `fn input-spec `@body) args#)]
(when-not (~output-spec output#)
(throw (ex-info "Нарушение на контракт"
{:function '~name
:input input#
:output output#})))
output#)))
;; Употреба
(defcontract add-positive
[a number? b number?] ;; Input spec
number? ;; Output spec
[a b]
(+ a b))
```
---
## 6. Модели за дизайн на API
### 6.1 Ring Handlers (Чисти функции)
```clojure
(defn wrap-logging [handler]
(fn [request]
(println "Request:" (:uri request))
(let [response (handler request)]
(println "Response:" (:status response))
response)))
(defn wrap-cors [handler]
(fn [request]
(let [response (handler request)]
(assoc response :headers
(merge (:headers response {})
{"Access-Control-Allow-Origin" "*"})))))
;; Чист handler
(defn handle-get-user [request]
{:status 200
:headers {"Content-Type" "application/json"}
:body (pr-str {:name "John" :email "john@example.com"})})
```
### 6.2 Middleware Stack
```clojure
(defn apply-middleware [handler middlewares]
(reduce
(fn [h middleware]
(middleware h))
handler
middlewares))
(def app
(-> handler-get-user
(apply-middleware [wrap-cors
wrap-logging
wrap-auth])))
```
### 6.3 Дефиниции на routes
```clojure
(def routes
[[:get "/users" list-users]
[:get "/users/:id" get-user]
[:post "/users" create-user]
[:put "/users/:id" update-user]
[:delete "/users/:id" delete-user]])
(defn match-route [method path]
(some
(fn [[m p handler]]
(when (and (= method m)
(re-matches (route->regex p) path))
{:handler handler
:params (extract-params p path)}))
routes))
```
### 6.4 Error Handling Middleware
```clojure
(defn wrap-exception [handler]
(fn [request]
(try
(handler request)
(catch Exception e
{:status 500
:headers {"Content-Type" "application/json"}
:body (pr-str {:error (ex-message e)
:data (ex-data e)})}))))
(defn wrap-not-found [handler]
(fn [request]
(let [response (handler request)]
(if (= (:status response) 404)
{:status 404
:body "Не е намерен"}
response))))
```
---
## 7. Рецепти за тестване
### 7.1 Property-Based тестване
```clojure
(defcommutative +
[a integer? b integer?]
(= (+ a b) (+ b a)))
(defassociative +
[a integer? b integer? c integer?]
(= (+ (+ a b) c) (+ a (+ b c))))
;; Идемпотентни операции
(defidempotent conj
[coll vector? item any?]
(= (conj (conj coll item) item)
(conj coll item)))
```
### 7.2 Test Fixtures с Random Data
```clojure
(defn with-sample-data [f]
(let [samples (gen/sample (s/gen ::user) 10)]
(doseq [sample samples]
(f sample))))
(t/use-fixtures :each with-sample-data)
(t/deftest user-validation-test
[sample]
(t/is (nil? (validate-user sample))))
```
### 7.3 Mutation тестване
```clojure
;; Просто mutation тестване
(defn mutate-and-test [original-fn test-fn mutation]
(let [mutated (mutation original-fn)]
(try
(test-fn mutated)
false ;; Тестът премина при мутация = лошо
(catch AssertionError _
true)))) ;; Тестът хвана мутацията = добро
;; Генератор на случайни мутации
(defn random-mutation [f]
(let [mutations [(fn [x] (inc x))
(fn [x] (dec x))
(fn [x] (* x 2))]]
(some #(% f) mutations)))
```
---
## 8. Рецепти за производителност
### 8.1 Batch обработка
```clojure
(defn batch-process [items batch-size f]
(into []
(mapcat f)
(partition-all batch-size items)))
;; Употреба
(batch-process (range 10000) 100
(fn [batch]
(mapv expensive-operation batch)))
```
### 8.2 Caching с TTL
```clojure
(defn make-ttl-cache [ttl-ms]
(let [cache (atom {})
cleanup (fn []
(let [now (System/currentTimeMillis)]
(swap! cache
(fn [m]
(into {}
(filter #(< (- now (val %)) ttl-ms))
m)))))]
(fn [f]
(fn [k]
(cleanup)
(if-let [entry (get @cache k)]
(val entry)
(let [result (f k)]
(swap! cache assoc k [(System/currentTimeMillis) result])
result))))))
(def cached-heavy-operation (make-ttl-cache 60000) heavy-operation)
```
### 8.3 Lazy File Processing
```clojure
(defn lazy-file-lines [filepath]
(line-seq (clojure.java.io/reader filepath)))
(defn lazy-csv-rows [filepath]
(map #(clojure.string/split % #",")
(lazy-file-lines filepath)))
;; Обработка на огромни файлове ред по ред
(into []
(comp
(drop 1) ;; Пропускане на хедър
(map #(update % 2 parse-long)) ;; Трансформиране на колона
(filter #(= "active" (% 3))))
(take 1000 (lazy-csv-rows "large-file.csv")))
```
### 8.4 Паралелна обработка на колекции
```clojure
(defn parallel-map [f coll n]
(let [parts (partition-all (/ (count coll) n) coll)
results (pmap #(doall (map f %)) parts)]
(apply concat results)))
;; С reducers за по-добра производителност
(require '[clojure.core.reducers :as r])
(defn parallel-reduce [f init coll]
(r/fold (/ (count coll) 4) f coll))
```
---
*Чист Clojure: Практически рецепти*
+289
View File
@@ -0,0 +1,289 @@
# Clojure/Nim: Native Clojure
> Същият език, който обичаш. Компилиран до нативен код. Без JVM.
---
## Какво е Clojure/Nim?
**Clojure/Nim** е пълен диалект на Clojure, който се компилира до нативен машинен код през Nim компилатора. Това не е интерпретатор — това е истински компилатор с пълен pipeline за оптимизация:
```
Твоят .clj файл
Reader (EDN парсер)
Разширяване на макроси (defmacro, syntax-quote, ->, ->>)
Emitter (Clojure AST → Nim изходен код)
Nim компилатор → C код
C компилатор → Нативен бинарен файл
```
Резултатът е един изпълним файл, често под **1 MB**, който стартира мигновено — **без JVM warmup**.
### Защо native?
| JVM Clojure | Clojure/Nim |
|-------------|-------------|
| Нуждае се от Java runtime | Самостоятелен бинарен файл |
| ~2-5 секунди startup | Мигновен старт |
| ~100-300 MB RAM | ~1-10 MB |
| JIT паузи | Ahead-of-time, предсказуем |
| Идеален за сървъри | Идеален за CLI, embedded, WASM |
Това не е играчка. Това е production компилатор с **276+ теста**, **persistent структури от данни (HAMT)**, **core.async канали** и **AI-асистиран workflow**.
---
## Инсталация
```bash
git clone https://gitlab.com/balvatar/lisp-nim.git
cd lisp-nim
make build
make check # всички тестове + примери
```
**Изисквания:** Nim ≥ 2.0, GCC или Clang, make.
Толкова. Няма Java. Няма Leiningen. Няма deps, които се свалят по десет минути.
---
## Първа програма
Създай `hello.clj`:
```clojure
(println "Здравей от native Clojure!")
(println (+ 1 2 3 4 5))
```
Изпълни:
```bash
$ ./cljnim run hello.clj
Здравей от native Clojure!
15
```
Забележи: програмата беше парсирана, разширена с макроси, емитирана като Nim, компилирана до C, компилирана до машинен код и изпълнена — всичко за под секунда.
---
## REPL: Два режима
### Човешки REPL
```bash
$ ./cljnim repl
user> (defn square [x] (* x x))
user> (square 7)
=> 49
user> (atom 42)
=> (atom 42)
user> :ai функция за фибоначи
🤖 Мисля...
💡 AI Предложение:
(defn fib [n]
(loop [a 0 b 1 i 0]
(if (= i n) a (recur b (+ a b) (inc i)))))
```
### JSON REPL (за AI агенти)
```bash
$ ./cljnim repl --json
{"status":"ready","ns":"user","mode":"json"}
> {"op":"eval","form":"(+ 1 2 3)"}
{"status":"ok","result":{"printed":"6"},"meta":{"ms":12}}
> {"tool":"cljnim/eval","args":{"form":"(defn greet [name] (str \"Hello \" name))"}}
{"status":"ok","result":{"type":"var","name":"greet"},...}
```
JSON REPL е проектиран за програмно взаимодействие. Всяка операция има структуриран вход и изход. AI агенти могат да откриват възможности, оценяват код, инспектират дефиниции и обработват batch форми без парсиране на човешки текст.
---
## AI-асистирана разработка
Clojure/Nim е първата Clojure имплементация, в която AI асистенцията е първокласна функция.
### Обяснение на грешки
Когато компилацията fail-не, компилаторът пита AI за помощ:
```bash
$ ./cljnim run broken.clj
Compilation failed
Error: identifier expected, but got 'keyword var'
💡 AI Предложение:
Грешката е защото `var` е запазена дума в Nim.
Оправи: Преименувай функцията на `my-var`.
```
### Генериране на код
Генерирай идиоматичен Clojure от описание:
```bash
$ ./cljnim ai "функция, която филтрира четните числа"
(defn filter-even [coll]
(loop [remaining coll result []]
(if (empty? remaining)
result
(let [x (first remaining)]
(recur (rest remaining)
(if (even? x) (conj result x) result))))))
```
### Настройка
```bash
export DEEPSEEK_API_KEY="sk-..."
# или OPENAI_API_KEY, или MIMO_API_KEY
```
---
## `loop` / `recur`: Истинска TCO
За разлика от JVM Clojure (който използва `recur`, за да избегне stack overflow, но все пак работи върху stack-based VM), Clojure/Nim компилира `loop`/`recur` до native `while` цикъл:
```clojure
(defn factorial [n]
(loop [acc 1 i n]
(if (= i 0)
acc
(recur (* acc i) (dec i)))))
```
Това генерира ефективен C код без функционални извиквания. **Истински O(1) stack space**.
---
## Cross-Compilation Target-и
Clojure/Nim може да таргетира множество платформи от един и същи изходен код:
### Нативен бинарен файл (по подразбиране)
```bash
./cljnim run program.clj
```
### JavaScript
```bash
./cljnim compile program.clj program.nim
nim js -o:program.js program.nim
node program.js
```
### C Shared Library
```bash
./cljnim compile-lib program.clj program.nim
nim c --app:lib -o:libprogram.so program.nim
```
### WASM (експериментално)
```bash
nim c -d:release --cpu:wasm32 --os:linux program.nim
```
Това е нещо, което JVM Clojure просто не може да направи.
---
## Persistent Структури от Данни
Clojure/Nim имплементира истински **Hash Array Mapped Trie (HAMT)** вектори и карти:
```clojure
(def v (vector 1 2 3))
(def v2 (conj v 4))
;; v => [1 2 3]
;; v2 => [1 2 3 4]
;; Structural sharing: O(log₃₂ n) обновления, не O(n) копия
```
Runtime-ът използва същите алгоритми като Clojure/JVM (32-way branching, path copying, tail optimization), но компилиран до bare metal.
---
## Конкурентност
### Atoms
```clojure
(def counter (atom 0))
(swap! counter inc) ;; => 1
(reset! counter 100) ;; => 100
(deref counter) ;; => 100
```
### Agents
```clojure
(def state (agent 0))
(send state + 10)
(await state)
(deref state) ;; => 10
```
### Канали (core.async)
```clojure
(def ch (chan 10))
(put! ch 42)
(take! ch) ;; => 42
(close! ch)
```
Всички примитиви за конкурентност работят както в компилирания runtime, така и в in-memory интерпретатора.
---
## Макроси, които работят
```clojure
(defmacro unless [condition body]
`(if (not ~condition)
~body))
(unless false
(println "Това се печата!"))
```
Threading макроси, `when-let`, `cond`, `doto`, `some->` — всички имплементирани като истински Clojure макроси, разширявани по време на компилация.
---
## Кога да използваш Clojure/Nim
| Use Case | Clojure/JVM | Clojure/Nim |
|----------|-------------|-------------|
| Големи уеб услуги | ✅ | ⚠️ (ранен етап) |
| CLI инструменти | ⚠️ (бавен старт) | ✅ (мигновен) |
| Embedded системи | ❌ | ✅ |
| WASM / браузър | ClojureScript | ✅ (native WASM) |
| Споделени библиотеки | ❌ | ✅ |
| AI agent scripting | ❌ | ✅ (JSON REPL) |
| Учене на Clojure | ✅ | ✅ (без JVM) |
---
## Допълнително четене
- [Основи](01-fundamentals.md) — Core Clojure концепции (валидни за всички диалекти)
- [Архитектура](../../docs/bg/02-architecture.md) — Как работи компилаторът вътрешно
- [AI Интеграция](../../docs/bg/03-ai-integration.md) — Детайли за AI функциите
- [API Справочник](../../docs/bg/04-api-reference.md) — Спецификация на JSON REPL протокола
---
*Clojure/Nim е доказателство, че не ти трябва виртуална машина, за да пишеш елегантен, функционален, immutable код. Трябва ти само добър компилатор.*
+238
View File
@@ -0,0 +1,238 @@
# Subject Index - Bulgarian
## А
- **Агенти (Agents)** - [11.3](bg/01-fundamentals.md#113-агенти-agents)
- **Алиасиране на namespaces** - [9.3](bg/01-fundamentals.md#93-отнасяне-и-импортиране)
- **Алокиране (памет)** - [8.2](bg/02-advanced.md#82-transient-структури-от-данни)
- **Анонимни функции** - [5.2](bg/01-fundamentals.md#52-анонимни-функции)
- **Аритности** - [5.1.2](bg/01-fundamentals.md#512-множество-арности)
- **Асинхронно програмиране** - [16](bg/01-fundamentals.md#16-coreasync), [4](bg/04-recipes.md#4-async-рецепти)
- **Атом (Atom)** - [11.1](bg/01-fundamentals.md#11-атоми-atoms), [5](bg/05-clojure-nim.md#конкурентност)
- **AI интеграция** - [5](bg/05-clojure-nim.md#ai-асистирана-разработка)
- **AI агенти** - [5](bg/05-clojure-nim.md#json-repl-за-ai-агенти)
- **Clojure/Nim** - [5](bg/05-clojure-nim.md) — Нативна компилация, AI, JSON REPL
- **Cross-compilation** - [5](bg/05-clojure-nim.md#cross-compilation-target-и) — JS, WASM, shared libraries
## Б
- **Батч обработка** - [8.5](bg/02-advanced.md#85-batch-обработка), [8.1](bg/04-recipes.md#81-batch-обработка)
- **Булеви стойности** - [4.4](bg/01-fundamentals.md#44-булеви-стойности)
## В
- **Вариадични функции** - [1.1](bg/02-advanced.md#11-вариадични-функции)
- **Вграждане на типове** - [12.3](bg/01-fundamentals.md#123-разширяване-на-съществуващи-типове)
- **Вектори (Vectors)** - [4.8](bg/01-fundamentals.md#48-вектори-vectors)
- **Вербална форма** - [3.6](bg/01-fundamentals.md#36-интервали-и-форматиране)
- **Взаимна рекурсия** - [1.4](bg/02-advanced.md#14-взаимна-рекурсия)
- **Видове диспечиране** - [13](bg/01-fundamentals.md#13-многометодни-функции)
- **Вложен достъп** - [2.1](bg/04-recipes.md#21-вложен-достъп-до-данни)
- **Вложени серии** - [2.3](bg/02-advanced.md#23-lazy-cons-и-реализация)
- **Всички (reduce)** - [7.3.3](bg/01-fundamentals.md#733-reduce)
- **Входни/изходни условия** - [1.6](bg/02-advanced.md#16-пред--и-пост-условия)
## Г
- **Генеративно тестване** - [14.4](bg/01-fundamentals.md#144-генеративно-тестване), [4.5](bg/02-advanced.md#45-генеративно-тестване)
- **Групиране** - [2.2](bg/04-recipes.md#22-групиране-и-агрегиране)
## Д
- **Дата структури** - [4](bg/01-fundamentals.md#4-структури-от-данни)
- **дебъг** - [8.5](bg/03-tooling.md#85-breakpoints)
- **Дебъгване** - [8](bg/03-tooling.md#8-техники-за-дебъгване)
- **def** - [3.3.1](bg/01-fundamentals.md#331-def)
- **defmacro** - [10.1](bg/01-fundamentals.md#101-какво-са-макросите)
- **defmethod** - [13.1](bg/01-fundamentals.md#131-дефиниране-на-многометодни-функции)
- **defmulti** - [13.1](bg/01-fundamentals.md#131-дефиниране-на-многометодни-функции)
- **defn** - [5.1.1](bg/01-fundamentals.md#511-основен-синтаксис)
- **defprotocol** - [12.1](bg/01-fundamentals.md#121-протоколи)
- **defrecord** - [12.2](bg/01-fundamentals.md#122-записи)
- **delay** - [11.6](bg/01-fundamentals.md#116-promises-и-delivered)
- **Деструктуриране** - [8](bg/01-fundamentals.md#8-деструктуриране)
- **диспечиране по поведение** - [13](bg/01-fundamentals.md#13-многометодни-функции)
- **Docker** - [6.3](bg/03-tooling.md#63-docker-интеграция)
- **doseq** - [6.2.4](bg/01-fundamentals.md#624-doseq-странични-ефекти)
- **dosync** - [11.2](bg/01-fundamentals.md#112-референции-refs)
- **dotimes** - [6.2.3](bg/01-fundamentals.md#623-for-list-comprehension)
- **drop** - [7.3.6](bg/01-fundamentals.md#736-take--drop)
- **drop-while** - [7.3.6](bg/01-fundamentals.md#736-take--drop)
## Е
- **Екосистема от библиотеки** - [7](bg/03-tooling.md#7-екосистема-от-библиотеки)
- **Едноредови коментари** - [3.5](bg/01-fundamentals.md#35-коментари)
- **Either модел** - [1.2](bg/04-recipes.md#12-eitherresult-модел)
## Ж
- **Жизнения цикъл** - [3.1](bg/04-recipes.md#31-service-модел-с-atoms)
## З
- **Затваряне (Closure)** - [5.4](bg/01-fundamentals.md#54-затваряния-closures)
- **Записи (Records)** - [12.2](bg/01-fundamentals.md#122-записи)
- **Зареждане на зависимости** - [2.1](bg/03-tooling.md#21-depsedn-референция)
## И
- **Идентичности** - [11](bg/01-fundamentals.md#11-конкурентност)
- **Изграждане и деплойване** - [6](bg/03-tooling.md#6-изграждане-и-деплойване)
- **Изключения** - [6.3](bg/01-fundamentals.md#63-обработка-на-изключения)
- **Итерация** - [6.2](bg/01-fundamentals.md#62-итерация)
- **Инсталация** - [2.1](bg/01-fundamentals.md#21-инсталация)
- **Интеграционно тестване** - [3.3](bg/03-tooling.md#33-тестови-namespace-и)
- **Инфраструктура за тестване** - [3](bg/03-tooling.md#3-инфраструктура-за-тестване)
## К
- **Канали (Channels)** - [16.1](bg/01-fundamentals.md#161-канали)
- **Кеширане** - [1.5](bg/01-fundamentals.md#15-мемоизация), [8.6](bg/02-advanced.md#86-предварително-зареждане-и-кеширане), [8.2](bg/04-recipes.md#82-caching-с-ttl)
- **Ключови думи (Keywords)** - [4.5](bg/01-fundamentals.md#45-ключови-думи-keywords)
- **Колекции** - [4.12](bg/01-fundamentals.md#412-библиотека-за-колекции)
- **Коментари** - [3.5](bg/01-fundamentals.md#35-коментари)
- **Композиране на функции** - [5.3](bg/01-fundamentals.md#53-функции-от-по-висок-ред)
- **Конкурентност** - [11](bg/01-fundamentals.md#11-конкурентност)
- **Контракти** - [5.3](bg/04-recipes.md#53-contract-тестване)
- **Конфигуриране** - [1.3](bg/02-advanced.md#13-аргументи-от-тип-ключова-дума)
- **Куриране** - [5.3](bg/04-recipes.md#53-contract-тестване)
## Л
- **Лениви серии** - [7.2](bg/01-fundamentals.md#72-мързеливи-серии), [2](bg/02-advanced.md#2-мързеливи-серии---задълбочено)
- **let** - [3.3.2](bg/01-fundamentals.md#332-let)
- **letfn** - [5.1.3](bg/01-fundamentals.md#513-променлив-брой-аргументи)
- **Литери** - [4.1](bg/01-fundamentals.md#41-числа)
- **Логване** - [8.6](bg/03-tooling.md#86-logging)
- **loop** - [6.2.2](bg/01-fundamentals.md#622-looprecur)
## М
- **Макроси** - [10](bg/01-fundamentals.md#10-макроси)
- **Мемоизация** - [1.5](bg/02-advanced.md#15-мемоизация)
- **Метаданни на функции** - [1.7](bg/02-advanced.md#17-метаданни-на-функции)
- **Множества (Sets)** - [4.10](bg/01-fundamentals.md#410-множества-sets)
- **Многометодни функции** - [13](bg/01-fundamentals.md#13-многометодни-функции)
- **Модел на състояние (State machine)** - [1.3](bg/04-recipes.md#13-state-machine-модел)
- **Мързелива консумация** - [2.3](bg/02-advanced.md#23-lazy-cons-и-реализация)
## Н
- **Наблюдение на състояние** - [8.4](bg/03-tooling.md#84-watching-state)
- **Намиране на библиотеки** - [7.6](bg/03-tooling.md#76-намиране-на-библиотеки)
- **Насоки за STM** - [11.7](bg/01-fundamentals.md#117-насоки-за-stm)
- **Независимост от типа** - [13.1](bg/01-fundamentals.md#131-дефиниране-на-многометодни-функции)
- **Неизменяемост** - [1.2.1](bg/01-fundamentals.md#121-неизменяемост-по-подразбиране), [4](bg/01-fundamentals.md#4-структури-от-данни)
- **Низове (Strings)** - [4.2](bg/01-fundamentals.md#42-низове)
- **Namespace** - [9](bg/01-fundamentals.md#9-пространства-от-имена)
## О
- **Обекти за серии** - [2.4](bg/02-advanced.md#24-seqable-обекти)
- **Обхождане на колекции** - [7.5](bg/01-fundamentals.md#75-обхождане-на-колекции)
- **Област на видимост** - [3.3.2](bg/01-fundamentals.md#332-let)
- **Операции с дървета** - [2.4](bg/04-recipes.md#24-tree-операции)
- **Оптимизация на производителността** - [8](bg/02-advanced.md#8-оптимизация-на-производителността)
- **Основни функции** - [5](bg/01-fundamentals.md#5-функции)
- **Отношения** - [13.3](bg/01-fundamentals.md#133-йерархии)
## П
- **Паралелизъм** - [7](bg/02-advanced.md#7-паралелизъм)
- **Персонализирани reducers** - [6.2](bg/02-advanced.md#62-използване-на-reducers)
- **Писане на редове** - [8.1](bg/03-tooling.md#81-print-дебъгване)
- **Предикати** - [4.12](bg/01-fundamentals.md#412-библиотека-за-колекции)
- **Предварително зареждане** - [8.6](bg/02-advanced.md#86-предварително-зареждане-и-кеширане)
- **Презареждане на код** - [4.1](bg/03-tooling.md#41-repl-driven-разработка), [4.2](bg/03-tooling.md#42-hot-loading-на-код)
- **Примитивни типове** - [4.1](bg/01-fundamentals.md#41-числа)
- **Проектна структура** - [1](bg/03-tooling.md#1-структура-на-проекта)
- **Променливи (Vars)** - [11.4](bg/01-fundamentals.md#114-променливи-vars)
- **Протоколи** - [12](bg/01-fundamentals.md#12-протоколи-и-записи)
- **Процеси** - [3.1](bg/04-recipes.md#31-service-модел-с-atoms)
## Р
- **Разширени функции** - [1](bg/02-advanced.md#1-разширени-функции)
- **Редуктори** - [6](bg/02-advanced.md#6-reducibles)
- **Референции (Refs)** - [11.2](bg/01-fundamentals.md#112-референции-refs)
- **Рецепти за async** - [4](bg/04-recipes.md#4-async-рецепти)
- **Рецепти за валидация** - [5](bg/04-recipes.md#5-рецепти-за-валидация)
- **Рецепти за данни** - [2](bg/04-recipes.md#2-рецепти-за-трансформация-на-данни)
- **Рецепти за производителност** - [8](bg/04-recipes.md#8-рецепти-за-производителност)
- **Рецепти за тестване** - [7](bg/04-recipes.md#7-рецепти-за-тестване)
- **Рецепти за управление на състояние** - [3](bg/04-recipes.md#3-рецепти-за-управление-на-състояние)
- **Резервно копие** - [4.3](bg/04-recipes.md#43-timeout-модели)
- **Рекursивност** - [6.2.1](bg/01-fundamentals.md#621-рекурсия)
- **REPL** - [2.2](bg/01-fundamentals.md#22-вашият-първи-clojure-проект), [15](bg/01-fundamentals.md#15-repl)
- **Роля** - [5.3](bg/04-recipes.md#53-contract-тестване)
## С
- **Свободни променливи** - [5.4](bg/01-fundamentals.md#54-затваряния-closures)
- **Серии (Sequences)** - [7](bg/01-fundamentals.md#7-серии-и-мързеливо-оценяване)
- **Символи (Symbols)** - [4.6](bg/01-fundamentals.md#46-символи-symbols)
- **Синтаксис цитат** - [10.2](bg/01-fundamentals.md#102-syntax-quote)
- **Специални форми** - [3.3](bg/01-fundamentals.md#33-специални-форми)
- **Списъци (Lists)** - [4.7](bg/01-fundamentals.md#47-списъци-lists)
- **Спретващо сери** - [2.2](bg/02-advanced.md#22-chunked-серии)
- **Средна работа** - [8.5](bg/02-advanced.md#85-batch-обработка)
- **Статус на веригата** - [3.4](bg/04-recipes.md#34-circuit-breaker)
- **Стек trace** - [8.2](bg/03-tooling.md#82-stack-traces)
- **Структури от данни** - [4](bg/01-fundamentals.md#4-структури-от-данни)
- **Събития** - [3.2](bg/04-recipes.md#32-event-sourcing)
## Т
- **Текстови низове** - [4.2](bg/01-fundamentals.md#42-низове)
- **Тестване** - [14](bg/01-fundamentals.md#14-тестване)
- **Типове** - [4.1](bg/01-fundamentals.md#41-числа)
- **Трансдюсъри** - [3](bg/02-advanced.md#3-трансдюсъри)
- **Трансформиране на данни** - [2](bg/04-recipes.md#2-рецепти-за-трансформация-на-данни)
## У
- **Управление на състояние** - [3](bg/04-recipes.md#3-рецепти-за-управление-на-състояние)
- **Уникални стойности** - [7.3.9](bg/01-fundamentals.md#739-distinct--sort--shuffle)
## Ф
- **Фабрични функции** - [12.2](bg/01-fundamentals.md#122-записи)
- **Философия на Clojure** - [1.4](bg/01-fundamentals.md#14-философията-на-clojure)
- **Филтриране** - [7.3.2](bg/01-fundamentals.md#732-filter--remove)
- **Форматиране** - [3.6](bg/01-fundamentals.md#36-интервали-и-форматиране)
- **Функции** - [5](bg/01-fundamentals.md#5-функции)
- **Функции от по-висок ред** - [5.3](bg/01-fundamentals.md#53-функции-от-по-висок-ред)
- **Функционално програмиране** - [1.2.2](bg/01-fundamentals.md#122-функционално-пограмиране)
## Х
- **Хигиена на макроси** - [10.7](bg/01-fundamentals.md#107-хгиена)
- **Хранилище на събития** - [3.2](bg/04-recipes.md#32-event-sourcing)
## Ц
- **Целочислени типове** - [4.1.1](bg/01-fundamentals.md#411-целочислени-типове)
- **Цикли** - [6.2](bg/01-fundamentals.md#62-итерация)
## Ч
- **Числа** - [4.1](bg/01-fundamentals.md#41-числа)
- **Числа с плаваща запетая** - [4.1.2](bg/01-fundamentals.md#412-числа-с-плаваща-запетая)
- **Често срещани модели** - [1](bg/04-recipes.md#1-често-срещани-модели)
## Ш
- **Шаблони** - [5.2](bg/04-recipes.md#52-schema-валидация)
## Щ
- **Щафета (pipeline)** - [4.1](bg/04-recipes.md#41-channel-pipeline)
## Ъ
- **Ъндъфи** - [3.2](bg/04-recipes.md#32-event-sourcing)
## Я
- **Ядро async** - [16](bg/01-fundamentals.md#16-coreasync)