I'm mostly a C/C++ programmer, which means that the majority of my experience is with procedural and object-oriented paradigms. However, as many C++ programmers are aware, C++ has shifted in emphasis over the years to a functional-esque style, culminating finally in the addition of lambdas and closures in C++0x.
Regardless, while I have considerable experience coding in a functional style using C++, I have very little experience with actual functional languages such as Lisp, Haskell, etc.
I've recently began studying these languages, because the idea of "no side-effects" in purely functional languages has always intrigued me, especially with regards to its applications to concurrency and distributed computing.
However, coming from a C++ background I'm confused as to how this "no side-effects" philsophy works with asynchronous programming. By asynchronous programming I mean any framework/API/coding style which dispatches user-provided event handlers to handle events which occur asynchronously (outside the flow of the program.) This includes asynchronous libraries such as Boost.ASIO, or even just plain old C signal handlers or Java GUI event handlers.
The one thing all of these have in common is that the nature of asynchronous programming seems to require the creation of side-effects (state), in order for the main flow of the program to become aware that an asynchronous event handler has been invoked. Typically, in a framework like Boost.ASIO, an event handler changes the state of an object, so that the effect of the event is propagated beyond the life-time of the event handler function. Really, what else can an event handler do? It can't "return" a value to the call point, because there is no call point. The event handler is not part of the main flow of the program, so the only way it can have any effect on the actual program is to change some state (or else
longjmp to another execution point).
So it seems that asynchronous programming is all about asynchronously producing side-effects. This seems completely at odds with the goals of functional programming. How are these two paradigms reconciled (in practice) in functional languages?