
On Tue, Aug 28, 2007 at 07:51:48PM +0200, Andrea Rossato wrote:
On Tue, Aug 28, 2007 at 10:08:58AM -0400, David Roundy wrote:
You're welcome! Basically, I just used the printf approach, combined with code review, in which I just searched for cases where eventLoop might have exited early. There's got to be a better idiom for writing an event loop. (so that exiting the loop is done explicitly, rather than implicitly... which would make it harder to exit the loop accidentally.)
yes, indeed. Since I suspect you already have an idea on how the idiom should look like, may I ask you: - what would you suggest? - ;-)
I'm not sure. My only idea would be to use exceptions to exit the loop. Then you could have something like (I'll write my example in IO, but you can extrapolate) eventLoop :: (EventType -> IO ()) -> IO () eventLoop job = forever (getNextEvent >>= job) `catchJust` breakException (\_ -> cleanup) forever a = a >> forever a exitLoop :: IO () where breakException should be a function that probably uses dynException to filter out only exceptions thrown by exitLoop. Another option would be to avoid exceptions and instead make the job return explicitly whether or not to continue eventLoop :: (EventType -> IO ContinueOrNot) -> IO () eventLoop job = do done <- getNextEvent >>= job case done of ExitNow -> cleanup KeepGoing -> eventLoop job data ContinueOrNot = ExitNow | KeepGoing This makes the code a bit cleaner, and also has the advantage of working in monads that don't support exceptions. It means that every branch of the job has to explicitly decide whether or not to keep going, but at least the compiler will enforce that you need to have a clear decision on each branch. But I'm not sure either of these is optimal. Exceptions are ugly. You could also (given you're in a state monad) throw a "stop now" flag into that state, which is perhaps better than either of these. Then you'd only need to specify exitLoop (or whatever you choose to call it)... -- David Roundy http://www.darcs.net