
Hi. I've been experimenting with using Reactive as the basis of a network daemon I'm working on, with the top-level type Event Packet -> Event Packet. I've run into a difficult-to-debug strictness problem with the Monad instance for EventG, at least when used together with makeEvent. Here's a minimal test program that shows the problem:
import FRP.Reactive import FRP.Reactive.LegacyAdapters import Control.Concurrent import Control.Monad
my_event :: IO (Event Char) my_event = do (char_sink, char_event) <- makeEvent =<< makeClock forkIO $ forever $ char_sink =<< getChar return char_event
main = do chars <- my_event adaptE $ do c <- chars ; return (print c)
Running this program consumes 100% of CPU and doesn't respond to input. On the other hand, replacing the last line with
adaptE $ print `fmap` chars
does what you'd expect (prints each character read from stdin as it is received). I'm pretty sure what's happening here is adaptE evaluating joinE, which is in turn evaluating its recursive call to joinE without being properly lazy and waiting for the next occurrence of Event (Event Char), leading to an infinite loop. I've played around with the definition of joinE, but I don't have a sufficiently good mental model of the evaluator to figure out what needs to become stricter or lazier to fix this problem. In any case, my changes have either resulted in stack overflows or evaluating mempty. Perhaps I am misunderstanding the contract for Event's Monad instance. Is there a reason why it shouldn't be used with makeEvent or even adaptE? mkUpdater would be a poor substitute for adaptE, since a network daemon doesn't have any obvious equivalent to a graphical program's idle loop; ideally the output should be driven by incoming packets. Thanks, Chris