
Here's how I do it:
data InteractiveState = InteractiveState { state_read :: IO Command , state_write :: Result -> IO () }
How about :
data InteractiveState io = InteractiveState { state_read :: io Command , state_write :: Result -> io () }
I guess you could, but I like it concrete.
Then you don't even depend on some specific monad. I understand you can always (always?) encapsulate what is done through a type class by using a data containing functions. But then, is this not even closer to OO programming, an object that carries its own methods with itself, possibly with the additional overhead that *each* instance would have its own private references to possibly identical functions.
No, because I don't think there are any objects? In fact, I'm not even sure what you mean. I'm assuming you have an event loop like: event_loop st = do cmd <- state_read st state_write st (calculate_response cmd) event_loop st calculate_response :: Command -> Result Since 'st' never changes (in my case it does have some changing values), you can just write: event_loop st = forever $ state_write st =<< calculate_response <$> state_read st There are no objects or private references here, and I'm not even sure what they mean in this context.