Как отмечает @KarlBielefeldt, функциональный подход к такой проблеме состоит в том, чтобы рассматривать ее как возвращающую новое состояние из предыдущего состояния. Сами функции не содержат никакой информации, поэтому они всегда будут обновлять состояние m до состояния n .
Я думаю, что вы находите это неэффективным, потому что вы предполагаете, что предыдущее состояние должно храниться в памяти при вычислении нового состояния. Обратите внимание, что выбор между написанием совершенно нового состояния или перезаписью старого на месте - это деталь реализации с точки зрения функционального языка.
Например, скажем, у меня есть список из миллиона целых чисел, и я хочу увеличить десятую на одну единицу. Копирование всего списка с новым номером на десятой позиции расточительно, вы правы; но это только концептуальный способ описания операции компилятору или интерпретатору языка. Компилятор или интерпретатор может взять первый список и просто переписать десятую позицию.
Преимущество описания операции таким образом заключается в том, что компилятор может рассуждать о ситуации, когда многие потоки хотят обновить один и тот же список в разных позициях. Если операция описана как «перейти в эту позицию и перезаписать то, что вы нашли», то именно программист, а не компилятор, отвечает за то, чтобы перезаписи не конфликтовали.
С учетом всего вышесказанного, даже в Хаскеле существует государственная монада, которая помогает моделировать ситуации, в которых «поддержание состояния» является более интуитивным решением проблемы. Но, пожалуйста, обратите внимание, что у некоторых проблем, которые, по вашему мнению, «по своей сути сохраняют состояние, например, запись в базу данных », есть неизменные решения, например Datomic . Это может быть удивительно, пока вы не поймете, что это концепция, а не обязательно ее реализация.