Здесь начинается серьёзное погружение. В императивном мире программа меняет состояние; в функциональном — преобразует данные чистыми функциями, ничего не портя на месте. Сложное собирается композицией простого, а в основании лежит λ-исчисление. Это язык, на котором пишут программы, чью корректность можно доказать.
Императивная программа — это последовательность команд, меняющих состояние: присвоить, увеличить, перезаписать. Функциональная — это композиция преобразований: данные проходят сквозь чистые функции, и на каждом шаге рождается новое значение, а старое остаётся нетронутым. Мир описывается не как «что изменить», а как «какое преобразование применить».
Для инженера это не стилистика, а способ совладать со сложностью. Когда ничего не мутирует исподтишка, рассуждать о программе можно локально: каждая функция понятна сама по себе. Именно поэтому функциональный подход становится опорой второй дуги курса — дуги о корректности.
Неизменяемость — оборотная сторона чистоты: данные не меняют на месте, а порождают новые версии. Это убирает целый класс ошибок (гонки, неожиданные мутации) и открывает дорогу безопасному параллелизму — что станет важным в дуге об устойчивых системах. На Elixir это естественно:
Композиция $h\circ g\circ f$ ассоциативна и имеет единицу (тождество) — те же законы, что у моноида из главы об алгебре. Поэтому большие конвейеры собираются предсказуемо. Функции высшего порядка (map, filter, reduce) обобщают это: они принимают функции как аргументы и применяют их к структурам.
В Elixir конвейер виден буквально — оператор |> передаёт значение дальше по цепочке преобразований:
Два кирпича: абстракция $\lambda x.\,e$ (функция от $x$ с телом $e$) и применение $(\lambda x.\,e)\,a$. Вычисление — это β-редукция: подставить аргумент вместо переменной.
$(\lambda x.\,e)\,a \;\to_\beta\; e[x := a]$
Тождество — $\lambda x.\,x$. Функции здесь — значения первого класса: их можно передавать, возвращать, складывать в структуры. Этого минимума достаточно для тьюринг-полноты — на чистых функциях выразимо любое вычисление. Отсюда и сила ФП: программа — это выражение, а не протокол изменений.
Моноид — ассоциативная операция с единицей. Списки под конкатенацией (единица — пустой список), числа под сложением (единица — ноль) — всё это моноиды, и потому их можно безопасно «сворачивать»:
$a \cdot (b \cdot c) = (a \cdot b) \cdot c,\qquad e \cdot a = a \cdot e = a$
Ассоциативность + единица. Даёт право сворачивать (reduce) в любом порядке и распараллеливать: $\mathrm{fold}$ по моноиду корректен независимо от группировки.
Структура, по которой можно отобразить, сохранив форму: $\mathrm{map}(f)\circ\mathrm{map}(g)=\mathrm{map}(f\circ g)$. Так композиция переносится внутрь контейнеров.
Это и есть мост из главы об алгебре: структуры и их законы — не абстракция ради абстракции, а гарантия, что большая программа собирается из малых частей без сюрпризов. Углубление: алгебраические типы данныхчитать →
Мы сменили оптику: программа — не последовательность изменений, а композиция преобразований. Чистота даёт локальное рассуждение, неизменяемость убирает скрытые мутации, композиция собирает сложное из простого, λ-исчисление даёт основание, а алгебраические законы — гарантии. Это и есть «мир как преобразование».
Но локального рассуждения мало для полной уверенности. Чтобы программа была гарантированно верной, нужны типы, тотальность и доказательства. Об этом — следующая глава: математически корректные программы.