Добрый человек указал вчера на статью "ФП в браузере". Статья хорошая. Читается легко, картинки классные. Если раньше не приходилось читать про достоинства ФП, то имеет смысл потратить время.
Однако, любители функциональщины так сильно напирают на борьбу с изменяемым состоянием, что это начинает напоминать афоризм про борьбу с перхотью посредством отсечения головы :) Даже приведенный в статье пример организации списка undo/redo-операций посредством иммутабельных списков заставил вспомить свой прошлый опыт. Ведь не так-то все и просто...
В конце 90-х довелось написать несколько приложений, которые поддерживали историю операций и позволяли делать операции undo. Undo-операции сохранялись в стеке. При инициировании Undo верхний элемент стека извлекался, проводилась модификация документа, точнее говоря, отменялось соответствующее изменение в документе. В общем-то ничего сложного, если бы не один небольшой нюанс :)
Результаты Undo должны были сказываться не только на самом содержимом документа, но еще и на состоянии редактора.
Например, после последнего изменения документ был сохранен на диск, после чего пользователь выполнил команду Undo. Теперь содержимое документа в памяти и на диске не совпадают. Это значит, что при попытке пользователя выйти из редактора нужно спросить, а не желает ли он сохранить изменения.
Или, напротив, пользователь сохранил документ, затем что-то исправил (документ изменен, нужно спрашивать о сохранении документа при выходе), потом выполнил Undo (документ вновь совпадает с тем, что на диске, ничего при выходе спрашивать не нужно).
Причем в свое время, когда практически все приложения были десктопными, отображать статус документа (т.е. сохранен или нет) было принято где-то в окне редактора (в заголовке, к примеру, или в строке состояния). Что означало, что когда пользователь выполняет Undo, то изменялся не только сам документ, но и следовало соответствующим образом поменять часть элементов UI.
Или вот еще поворот разговора: допустим, Undo/Redo операции лежат в одном списке и есть текущая позиция в нем. При выполнении Undo позиция смещается влево, при последующем Redo -- вправо.
Ведь очевидно же, что Undo/Redo-список будет не простым списком. Допустим, мы сделали четыре действия, Undo-список пополнился четырьмя элементами:
a1 --> a2 --> a3 --> a4
* <-- текущая позиция
Выполняем два Undo и текущая позиция смещается на две позиции влево:
a1 --> a2 --> a3 --> a4
* <-- текущая позиция
Если мы теперь инциируем Redo, то текущая позиция сместиться на один элемент вправо:
a1 --> a2 --> a3 --> a4
* <-- текущая позиция
Но если здесь мы не будем делать еще один Redo, а сделаем новое действие над документом, то у нас появится "развилка" -- три элемента старых, к которым будет приписан еще один новый:
a1 --> a2 --> a3 ... a4 <-- между a3 и a4 теперь нет связи, за a3 следует a5
\
`---> a5
* <-- текущая позиция
Но что делать с тем старым Undo/Redo элементом a4, который уже не нужен, и к которому возвращаться уже нет смысла? Его ведь нужно выкидывать:
a1 --> a2 --> a3 --> a5
* <-- текущая позиция
Ну и что это будет если не модификация иммутабельного undo/redo списка? ;)
PS. Давно пытаюсь понять, могут ли существовать полноценные ФЯ без сборки мусора. Такое ощущение, что нет. А это означает, что программам, написанным в функциональном стиле, для нормальной работы нужно будет от 2-х до 4-х раз больше ОП, чем аналогам на императивных языках с ручным управлением памятью. Только вот не знаю, вернутся ли когда-нибудь времена, когда память вновь станет ресурсом...
Комментариев нет:
Отправить комментарий