I’m considering converting a C# app to Haskell as my first “real” Haskell project. However I want to make sure it’s a project that makes sense. The app collects data packets from ~15 serial streams that come at around 1 kHz, loads those values into the corresponding circular buffers on my “context” object, each with ~25000 elements, and then at 60 Hz sends those arrays out to OpenGL for waveform display. (Thus it has to be stored as an array, or at least converted to an array every 16 ms). There are also about 70 fields on my context object that I only maintain the current (latest) value, not the stream waveform.
There are several aspects of this project that map well to Haskell, but the thing I worry about is the performance. If for each new datapoint in any of the streams, I’m having to clone the entire context object with 70 fields and 15 25000-element arrays, obviously there’s going to be performance issues.
Would I get around this by putting everything in the IO-monad? But then that seems to somewhat defeat the purpose of using Haskell, right? Also all my code in C# is event-driven; is there an idiom for that in Haskell? It seems like adding a listener creates a “side effect” and I’m not sure how exactly that would be done.
Yes, you would probably want to use the IO monad for mutable data. I don’t believe the ST monad is a good fit for this problem space because the data updates are interleaved with actual IO actions (reading input streams). As you would need to perform the IO within ST by using
unsafeIOToST, I find it preferable to just use IO directly. The other approach with ST is to continually thaw and freeze an array; this is messy because you need to guarantee that old copies of the data are never used.Although evidence shows that a pure solution (in the form of
Data.Sequence.Seq) is often faster than using mutable data, given your requirement that data be pushed out to OpenGL, you’ll possible get better performance from working with the array directly. I would use the functions fromData.Vector.Storable.Mutable(from the vector package), as then you have access to theForeignPtrfor export.You can look at arrows (Yampa) for one very common approach to event-driven code. Another area is Functional Reactivity (FRP). There are starting to be some reasonably mature libraries in this domain, such as Netwire or reactive-banana. I don’t know if they’d provide adequate performance for your requirements though; I’ve mostly used them for gui-type programming.