Функциональное программирование на основе событий
У меня возникают проблемы при написании кода GUI, управляемого событиями, в функциональном стиле с использованием Clojure и Seesaw. В частности, я не могу понять, как передать состояние программы без использования глобальных переменных или какого-либо другого неприятного взлома. Мой нынешний подход выглядит примерно так:
(defn event-handler [gui-state event]
(update-gui! (get-new-state gui-state event)))
(defn update-gui! [gui-state]
(remove-all-listeners (gui-state :button))
(seesaw.core/listen (gui-state :button)
:action
(partial event-handler gui-state)))
Он устанавливает прослушиватель событий в соответствующем компоненте с частично примененной функцией для улучшения состояния и обновления графического интерфейса, включая удаление старого прослушивателя. Хотя кажется, что это работает, мне это не очень нравится, отчасти потому, что я не могу передать сам слушатель в состоянии (так как он не создан до тех пор, пока я уже не определил состояние), поэтому удаление старого слушателя требует удаление всех слушателей, которые могут вызвать проблемы по мере роста программы.
Самое близкое решение, которое я нашел в Интернете, находится в этом ответе, но я не знаю, как обрабатывать события как поток, как это показано. Я уверен, что должно быть лучшее решение, чем мой нынешний подход, но я не могу понять, что.
Может кто-нибудь показать мне, как я могу реагировать на события пользовательского ввода, все еще следуя функциональному стилю?
1 ответ
Потоки из связанного ответа кажутся аналогом каналов core.async.
Вместо удаления всех слушателей каждое событие может быть передано в канал, в который помещены подробности события. Этот же канал должен идти к логическому обработчику кнопки, откуда он будет повторно взят.