反应香蕉:国家monad或不?
我有一个基于反应香蕉的界面(WX)。 现在我对如何真正管理状态提出了不同的问题:
我应该将状态视为我在代码中定义的Behavior
吗?
如果状态也依赖于外部“事件”,不仅考虑到IORef,与GUI相关会更好吗?
或者我可以使用State Monad吗? 直到现在我看到的所有例子都定义了IO环境中的网络。 有没有任何意义的State Monad
和如何? 随着Moment
?
我应该将状态视为我在代码中定义的行为吗?
对于大多数场景,您确实需要将Behavior
用于状态。 在GUI应用程序中,您经常需要更新状态以响应接口事件。 另外,关键的是,国家在事件发生之间必须保持现状, State
不允许这样做。 更具体地说,对事件发生作出反应而不是更新Behavior
的标准方式是通过reactimate
函数:
reactimate :: Frameworks t => Event t (IO ()) -> Moment t ()
要执行的操作是IO ()
类型。 虽然可以使用runStateT
运行StateT s IO
使用计算reactimate
,计算将是自包含的,你不会有它用来提供在其他地方通过国家。 使用Event
s通过反应式香蕉玻璃钢接口更新Behavior
时,不会出现此问题: Behavior
在您需要再次使用之前一直存在。
如果状态也依赖于外部“事件”,不仅考虑到IORef,与GUI相关会更好吗?
不必要。 在许多情况下,您可以使用Reactive.Banana.Frameworks
的工具(如fromAddHandler
和newEvent
创建在发生外部I / O操作时触发的Event
。 这样,您可以将这些操作集成到您的活动网络中。 一个典型的例子就是一个计时器:反应式香蕉没有内置的时间概念,但是您可以引入一个通过定期发生的I / O操作触发的刻度事件。
这就是说,在某些情况下,你可能还是想用...
... IORef
S(或其他类型的可变变量,如MVar
S),如果你必须使用一个库的界面,无论出于何种原因,限制您使用事件自由反应能力Behavior
S和reactimate
。 前一段时间,关于这个涉及hArduino
的场景有一个非常好的问题。 这两个答案表现出不同但精神相似的方式,在不利的情况下建立有用的事件网络。
... StateT
如果你有一些独立的有状态算法,并且其结果不会在你的事件网络中的其他地方使用,那么你可以用runStateT
运行它并将它粘贴在一个reactimate
通话中。 愚蠢的例子:沿着这些线路进行reactimate
的IO ()
行为:
displayMessageBox . show =<< evalStateT someStateComputation initialState