我正在考虑将C#应用程序转换为Haskell作为我的第一个"真正的"Haskell项目.但是我想确保它是一个有意义的项目.应用程序收集来自大约1 kHz的~15个串行流的数据包,将这些值加载到我的"上下文"对象上的相应循环缓冲区中,每个缓冲区包含~25000个元素,然后以60 Hz将这些数组发送到OpenGL for波形显示.(因此,它具有被存储为阵列,或者至少转化成每16毫秒阵列).我的上下文对象上还有大约70个字段,我只维护当前(最新)值,而不是流波形.
这个项目有几个方面可以很好地映射到Haskell,但我担心的是性能.如果对于任何流中的每个新数据点,我必须使用70个字段和15个25000个元素数组克隆整个上下文对象,显然会出现性能问题.
我可以通过将所有内容放入IO-monad来解决这个问题吗?但那似乎在某种程度上打败了使用Haskell的目的,对吧?我在C#中的所有代码都是事件驱动的; 在哈斯克尔有没有成语?似乎添加一个监听器会产生"副作用",而我不确定该怎么做.
看看这个链接,在"ST monad"部分下:
http://book.realworldhaskell.org/read/advanced-library-design-building-a-bloom-filter.html
回到"修改数组元素"一节,我们提到修改不可变数组非常昂贵,因为它需要复制整个数组.使用UArray不会改变这一点,那么我们可以做些什么来降低可承受水平的成本呢?
在命令式语言中,我们只需修改数组的元素; 这也是我们在Haskell中的方法.
Haskell提供了一个名为ST的特殊monad,它允许我们以可变状态安全地工作.与State monad相比,它具有一些强大的附加功能.
我们可以解冻一个不可变数组来提供一个可变数组; 修改可变数组到位; 我们完成后冻结一个新的不可变数组.
...
IO monad还提供这些功能.两者之间的主要区别在于ST monad是有意设计的,这样我们就可以将它从它中恢复为纯Haskell代码.
因此应该可以就地修改,并且它毕竟不会破坏使用Haskell的目的.
是的,您可能希望将IO monad用于可变数据.我不相信ST monad非常适合这个问题空间,因为数据更新与实际的IO操作(读取输入流)交错.由于您需要通过使用在ST中执行IO unsafeIOToST,我发现最好直接使用IO.ST的另一种方法是不断解冻和冻结阵列; 这很麻烦,因为您需要保证永远不会使用旧的数据副本.
虽然有证据表明纯解(以形式Data.Sequence.Seq)通常比使用可变数据更快,但鉴于您要求将数据推送到OpenGL,您可以直接使用数组获得更好的性能.我将使用Data.Vector.Storable.Mutable(来自矢量包)中的函数,因为您可以访问ForeignPtrfor导出.
您可以查看箭头(Yampa),了解一种非常常见的事件驱动代码方法.另一个领域是功能反应性(FRP).这个领域开始有一些相当成熟的库,例如Netwire或reactive-banana.我不知道他们是否能为你的要求提供足够的表现; 我主要用它们进行gui型编程.