Функциональное программирование:государство против.переназначение

StackOverflow https://stackoverflow.com/questions/353912

Вопрос

Мне нужна помощь, чтобы разобраться в разнице между моим нынешним представлением о состоянии ООП и тем, как это было бы реализовано в функциональном языке, таком как Haskell или Clojure.

Если использовать банальный пример, предположим, что мы имеем дело с упрощенными объектами/структурами банковских счетов/что-то еще.В языке ООП у меня был бы некоторый класс, содержащий ссылку на BankAccount, который имел бы переменные экземпляра для таких вещей, как процентная ставка, и такие методы, как setInterestRate(), которые изменяют состояние объекта и обычно ничего не возвращают.Скажем, в Clojure у меня была бы структура банковского счета (прославленная хэш-карта) и специальные функции, которые принимают параметр банковского счета и другую информацию и возвращают новую структуру.Таким образом, вместо изменения состояния исходного объекта теперь возвращается новый с желаемыми изменениями.

Так...что мне с этим делать?Перезаписать любую переменную, ссылающуюся на старый банковский счет?Если да, то есть ли у этого преимущества перед подходом ООП с изменением состояния?В конце концов, в обоих случаях кажется, что есть переменная, которая ссылается на объект с необходимыми изменениями.Я, будучи умственно отсталым, имею лишь смутное представление о том, что происходит.

Надеюсь, это имело смысл, спасибо за любую помощь!

Это было полезно?

Решение

В чисто функциональном стиле вы никогда не будете перезаписывать переменные.

Аналогией может быть пространство-время в физике.Если рассматривать мир как 3D, то у объектов нет фиксированного положения — они движутся со временем.Поэтому, чтобы применить математику к физическому миру, мы добавляем временное измерение и рассматриваем значения различных свойств в определенное время.При этом мы превратили объекты нашего исследования в константы.Точно так же в программировании можно добиться концептуальной простоты работы с неизменяемыми значениями.Объекты, имеющие идентичность в реальном мире, можно моделировать как последовательность неизменяемых значений (состояния объекта в возрастающие моменты времени), а не как одно изменяющееся значение.

Конечно, детали того, как связать последовательность значений с «идентичностью объекта», могут быть немного запутанными.В Хаскеле есть Монады которые позволяют моделировать состояние. Функциональное реактивное программирование это более буквальная попытка моделирования объектов в мире с чистыми функциональными обновлениями, что, на мой взгляд, является очень многообещающим направлением программирования.

Отмечу, что Clojure, в отличие от Haskell, не является чистым, и вы можете обновлять переменные, как вы предложили.Если вы обновляете только несколько переменных на высоком уровне, вы, вероятно, все равно будете пользоваться многими преимуществами концептуальной простоты функционального программирования.

Другие советы

Предположительно, в мире объектно-ориентированного программирования у вас есть цикл, и вы снова и снова изменяете эти банковские счета в ответ на запросы.Предположим, у вас есть целый портфель счетов типа «Портфель».Тогда в Haskell вы бы написали чистую функцию

updatePortfolio :: Request -> Portfolio -> Portfolio

А ваш основной цикл может читать запросы со стандартного ввода и поддерживать ваше портфолио в актуальном состоянии.(Этот пример бесполезен, если вы не умеете писать портфолио, но он проще.)

readRequest :: IO Request  -- an action that, when performed, reads a Request with side effects

main :: Portfolio -> IO ()  -- a completely useless program that updates a Portfolio in response to a stream of Requests

main portfolio = do req <- readRequest
                    main (updatePortfolio req)

и теперь я надеюсь, что вы видите, что случилось с вашим изменчивым состоянием:в типичной функциональной программе состояние, в котором изменения передаются в качестве параметра функции.Когда состояние изменяется, вы делаете новый вызов функции.Вызов находится в хвостовой позиции (вы можете найти «правильный хвостовой вызов»), поэтому он не использует никаких дополнительных ресурсов, и фактически, когда компилятор генерирует ассемблерный код, он генерирует цикл и сохраняет указатель на постоянно меняющийся портфель в реестре.

Это очень игрушечный пример, но я надеюсь, что он даст вам немного представления о функциональном языке.

Так...что мне с этим делать?Перезаписать любую переменную, ссылающуюся на старый банковский счет?

Да

Если да, то есть ли у этого преимущества перед подходом ООП с изменением состояния?

Допустим, вычисление любого действия, которое вы выполняете над этой структурой, занимает много времени, и что-то происходит на полпути, и вам нужно вернуться к исходной структуре, или вычисление вызвало ошибку.Учитывая интерпретацию ОО, которую вы мне представили (с использованием ссылки, потому что у вас может быть неизменяемый объектно-ориентированный язык), данные могут быть повреждены - это неизвестно, если в результате неудачного вызова функции не было получено достаточно информации, и давайте предположим, что это не удалось. плохо.При функциональном подходе вы точно знаете, что исходная структура данных правильна, поскольку изначально вы сделали копию.

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

Кроме того, мы можем сэкономить место, используя данные из другой структуры, из которой мы копируем.Классический пример — добавление элемента в начало списка.Если у нас есть указатель на второй элемент и указатель на первый элемент, мы можем ссылаться на оба списка только с размером первого (см. ниже).Без неизменности мы не можем этого гарантировать.

        b__
           |  
a -> [6|] -+-> [5|] -> [4|] -> [3|] -> [2|] -> [1|x]

Посмотрите на Haskell, который является чисто функциональным языком — в нем нет никаких переназначений, а также других побочных эффектов:чтобы выполнить ввод-вывод, в IO-монада построить его фактически заменяет Реальный мир с новым экземпляром мира, который, например, имеет новый текст, отображаемый в консоли.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top