7

我有一个基于 Reactive Banana 的界面(WX)。现在我对如何真正管理状态有不同的疑问:

  1. 我应该将状态视为Behavior我在代码中定义的 s 吗?

  2. 如果状态也依赖于外部“事件”,那么考虑 IORef 不仅与 GUI 相关会更好吗?

  3. 或者我可以使用 State Monad 吗?到目前为止,我看到的所有示例都定义了 IO 环境中的网络。有任何意义堆栈State Monad和如何?与Moment

4

1 回答 1

4

我应该将状态视为我在代码中定义的行为吗?

对于大多数情况,您确实希望将Behaviors 用于状态。在 GUI 应用程序中,您经常需要更新状态以响应界面事件。此外,至关重要的是,状态必须在事件发生之间保持存在,并且State不允许这样做。更具体地说,除了更新 a 之外,对事件发生做出反应的标准方法Behavior是通过reactimate函数:

reactimate :: Frameworks t => Event t (IO ()) -> Moment t ()

要执行的操作是类型IO ()。虽然可以使用runStateT来运行StateT s IO计算reactimate,但计算将是自包含的,并且您将无法将其使用的状态传递给其他地方。使用 s通过 reactive-banana FRP 接口Event更新s时不会出现此问题: s 保留在那里,直到您需要再次使用它们。BehaviorBehavior

如果状态也依赖于外部“事件”,那么考虑 IORef 不仅与 GUI 相关会更好吗?

不必要。在许多情况下,您可以使用Reactive.Banana.Frameworks诸如fromAddHandler和中的工具newEvent来创建Event在外部 I/O 操作发生时触发的 s。这样您就可以将此类操作集成到您的事件网络中。一个典型的例子是计时器:reactive-banana 没有内置的时间概念,但是您可以引入一个滴答事件,该事件通过定期发生的 I/O 操作触发。

也就是说,在某些情况下,您可能仍想使用...

  • ... IORefs(或其他类型的可变变量,例如MVars),如果您必须使用带有接口的库,无论出于何种原因,该接口都会限制您使用Behaviors 和对事件做出自由反应的能力reactimate。前段时间有一个非常好的问题,关于这种场景涉及hArduino. 那里的两个答案显示了在不利情况下拥有有用事件网络的不同但在精神上相似的方法。

  • ...StateT如果您有一些自包含的有状态算法并且其结果不会在您的事件网络中的其他地方使用,那么您可以运行它runStateT并将其粘贴在reactimate调用中。愚蠢的例子:沿着这些路线IO ()采取行动:reactimate

    displayMessageBox . show =<< evalStateT someStateComputation initialState
    
于 2015-09-01T18:14:04.823 回答