Счётчик как последовательность состояний

В императивном подходе переменная обычно похожа на ячейку: в ней лежит число, и команда заменяет его новым. В функциональном стиле значение рассматривают иначе — как неизменяемое состояние. Прибавление единицы не переписывает прежний счётчик, а вычисляет следующий: из `5` получается `6`. Старое значение при этом остаётся доступным, если на него ещё кто-то ссылается.

Это меняет способ описания программы. Вместо вопроса «что изменилось в этой переменной?» можно проследить цепочку: состояние `5` → операция увеличения → состояние `6`. Так проще воспроизвести ошибку: известны входные данные и функция, которая должна выдать результат.

Почему копия не обязательно означает лишнюю работу

Если счётчик — отдельное число, создать новое значение дёшево. С большими структурами данных буквальное копирование всего содержимого при каждом обновлении было бы затратным. Поэтому многие функциональные языки и библиотеки используют структурное разделение: новая версия сохраняет ссылки на неизменившиеся части старой, а заново создаётся только изменённая часть.

Например, при обновлении одного поля в большой записи остальные поля могут быть общими для обеих версий. Программа получает логически отдельные состояния, не дублируя каждый байт данных.

Что это даёт и чего стоит

Неизменяемые значения уменьшают риск, что один участок программы незаметно испортит данные, которыми пользуется другой. Это особенно полезно при параллельной работе: нескольким задачам проще безопасно читать одно состояние, если никто не может изменить его на месте. Обратная сторона — дополнительные объекты и необходимость выбирать структуры данных, рассчитанные на частые обновления.

Поэтому новая версия счётчика — не просто стилистическая замена операции присваивания. Она превращает обновления в явную историю состояний, а цена такого подхода зависит от того, как именно устроены данные и их копирование.