Я научился программировать прежде всего с точки зрения ООП (как и большинство из нас, я уверен), но я потратил много времени, пытаясь научиться решать проблемы функциональным способом. Я хорошо понимаю, как решать вычислительные задачи с помощью FP, но когда дело доходит до более сложных задач, я всегда возвращаюсь к необходимости изменяемых объектов. Например, если я пишу симулятор частиц, я хочу обновить «объекты» частиц с изменяемой позицией. Как по сути проблемы «с состоянием» обычно решаются с помощью методов функционального программирования?
functional-programming
Эндрю Мартин
источник
источник
Ответы:
Функциональные программы очень хорошо обрабатывают состояние, но требуют другого взгляда на него. В качестве примера вашей позиции следует учитывать, что ваша позиция должна быть функцией времени вместо фиксированного значения . Это хорошо работает для частиц, следующих по фиксированному математическому пути, но вам требуется другая стратегия для обработки изменения пути, например, после столкновения.
Основная стратегия здесь - вы создаете функции, которые принимают состояние и возвращают новое состояние . Таким образом, симулятор частиц будет функцией, которая принимает
Set
частицы в качестве входных данных и возвращает новыеSet
частицы после временного шага. Затем вы просто повторно вызываете эту функцию с ее входом, установленным на предыдущий результат.источник
Как отмечает @KarlBielefeldt, функциональный подход к такой проблеме состоит в том, чтобы рассматривать ее как возвращающую новое состояние из предыдущего состояния. Сами функции не содержат никакой информации, поэтому они всегда будут обновлять состояние m до состояния n .
Я думаю, что вы находите это неэффективным, потому что вы предполагаете, что предыдущее состояние должно храниться в памяти при вычислении нового состояния. Обратите внимание, что выбор между написанием совершенно нового состояния или перезаписью старого на месте - это деталь реализации с точки зрения функционального языка.
Например, скажем, у меня есть список из миллиона целых чисел, и я хочу увеличить десятую на одну единицу. Копирование всего списка с новым номером на десятой позиции расточительно, вы правы; но это только концептуальный способ описания операции компилятору или интерпретатору языка. Компилятор или интерпретатор может взять первый список и просто переписать десятую позицию.
Преимущество описания операции таким образом заключается в том, что компилятор может рассуждать о ситуации, когда многие потоки хотят обновить один и тот же список в разных позициях. Если операция описана как «перейти в эту позицию и перезаписать то, что вы нашли», то именно программист, а не компилятор, отвечает за то, чтобы перезаписи не конфликтовали.
С учетом всего вышесказанного, даже в Хаскеле существует государственная монада, которая помогает моделировать ситуации, в которых «поддержание состояния» является более интуитивным решением проблемы. Но, пожалуйста, обратите внимание, что у некоторых проблем, которые, по вашему мнению, «по своей сути сохраняют состояние, например, запись в базу данных », есть неизменные решения, например Datomic . Это может быть удивительно, пока вы не поймете, что это концепция, а не обязательно ее реализация.
источник
Подписка на правильную модель мышления помогает лучше думать и управлять состоянием. На мой взгляд, лучшая ментальная модель - это флипбук . После этого вы поймете, что FP в значительной степени опирается на постоянные структуры данных, которые фиксируют состояние мира, и что функции используются для перехода в это состояние без каких-либо изменений.
Rich Hickey освещает эти идеи:
Есть и другие разговоры, но это должно направить вас в правильном направлении.
источник
При написании больших и умеренно больших приложений я часто находил полезным различать разделы приложения с состоянием и от состояния без состояния.
Классы / структуры данных в разделе с сохранением состояния хранят данные приложения, а функции в этом разделе работают с неявным знанием данных приложения.
Классы / структуры данных / функции в разделе без сохранения состояния предназначены для поддержки чисто алгоритмических аспектов приложения. У них нет неявного знания данных приложения. Они работают в чисто функциональной природе. Части приложения с состоянием могут испытывать изменение состояния как побочный эффект запуска функций в разделе приложения без состояния.
Сложнее всего выяснить, какие классы / функции поместить в раздел без сохранения состояния и какие классы / функции поместить в раздел с сохранением состояния, а также иметь дисциплину для помещения их в отдельные файлы / библиотеки.
источник