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