Nothing wrong with writing the gist of your program written in functional way, keeping things immutable, allowing for orderless execution and lazy evaluation. But because your program interfaces with the real, consequential world it must realise all that computation at the pivot points where there is I/O and it suddenly matters that the lazy evaluation is complete.
Have a procedural loop to drive your events and other practical stuff and, from there, launch functional computations to calculate a completely or partially new state for your program. Keep things mostly immutable but do mutation in certain specific locations where it makes sense.
Clojure is good at drawing the line where the programmer sees it fit best. Multi-paradigm has always beaten pure ideologies hands down when it comes to delivering useful programs that actually work without making programmers do mental gymnastics for the sake of purity. (They should reserve their efforts to be mentally gymnast in the real-world problem they're solving.)
You don't want to write all of your program in object-oriented, procedural, functional, declarative, or whatever paradigm you have a thing for. They all do some things well and suck at others. Use them like tools, the right one for the right job.