我有一个基于Reactive Banana的界面(WX)。 现在我对如何真正管理状态有不同的疑问:
我应该将状态视为我在代码中定义的Behavior
吗?
如果状态依赖于外部“事件”,考虑到IORef,不仅与GUI相关会更好吗?
或者我可以使用State Monad吗?我到目前为止看到的所有示例都在IO环境中定义了网络。有任何感觉堆栈State Monad
以及如何?使用Moment
?
答案 0 :(得分:4)
我应该将状态视为我在代码中定义的行为吗?
对于大多数情况,您确实希望将Behavior
用于状态。在GUI应用程序中,您通常希望更新状态以响应接口事件。此外,至关重要的是,国家必须在事件发生之间保持存在,并且State
不允许这样做。更具体地说,对事件发生做出反应而不是更新Behavior
的标准方法是通过reactimate
函数:
reactimate :: Frameworks t => Event t (IO ()) -> Moment t ()
要执行的操作属于IO ()
类型。虽然可以使用runStateT
使用StateT s IO
运行reactimate
计算,但计算将是自包含的,并且您不会使用它可用的状态通过别处。使用Event
通过reactive-banana FRP接口更新Behavior
时不会出现此问题:Behavior
仍保留在那里,直到您需要再次使用它们为止。
如果州取决于外部"事件"考虑到IORef,不仅与GUI相关会更好吗?
不一定。在许多情况下,您可以使用Reactive.Banana.Frameworks
中的工具(例如fromAddHandler
和newEvent
)来创建在发生外部I / O操作时触发的Event
。这样,您就可以将此类操作集成到您的事件网络中。一个典型的例子是a timer:reactive-banana没有内置的时间概念,但你可以引入一个通过定期发生的I / O操作触发的tick事件。
那就是说,在某些情况下你可能仍然想要使用......
... IORef
s(或其他类型的可变变量,例如MVar
s),如果您必须使用具有接口的库,无论出于何种原因,该接口会限制您使用Behavior
和reactimate
自由地对事件做出反应的能力。不久前有a very nice question about such a scenario involving hArduino
。这两个答案显示出不同的,但在精神上相似的方式,在不利的情况下建立有用的事件网络。
... StateT
如果你有一些自包含的有状态算法,并且其结果不会在你的事件网络的其他地方使用,那么你可以用{{{}运行它1}}并将其粘贴在runStateT
电话中。愚蠢的例子:reactimate
中的IO ()
行动沿着以下几行:
reactimate