I'm having trouble writing event driven GUI code in a functional style, using Clojure and Seesaw. Specifically, I can't figure out how to pass the state of the program around without using globals, or some other unpleasant hack. My current approach is something like this:
(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)))
It sets an event listener on the relevant component, with a partially applied function to advance the state and update the gui, including removing the old listener. Although this seems to be working, I don't really like it, partly because I can't pass the listener itself in the state (since it's not constructed until after I've already defined the state), so removing the old listener requires removing all listeners, which could cause problems as the program grows.
The closest solution I've found online is in this answer, but I don't know how to handle events as a stream like it shows. I'm sure there must be a better solution than my current approach, but I can't figure out what.
Can anyone show me how I can respond to user input events while still following a functional style?