活性香蕉:状态monad与否?

Ran*_*ize 7 haskell reactive-banana

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

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

  2. 如果状态也取决于外部"事件",考虑到IORef,不仅与GUI相关会更好吗?

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

dup*_*ode 4

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

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

reactimate :: Frameworks t => Event t (IO ()) -> Moment t ()
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

  • ...StateT如果您有一些独立的有状态算法,并且其结果不会在事件网络中的其他地方使用,以便您可以运行它并将其runStateT保留在reactimate调用中。愚蠢的例子:按照以下方式IO ()进行的操作reactimate

    displayMessageBox . show =<< evalStateT someStateComputation initialState
    
    Run Code Online (Sandbox Code Playgroud)