QStateMachine框架提供了一种很好的声明方式来定义基于有状态事件的应用程序。即,然后发生一个事件,它执行一个回调(实际上它触发一个信号,但这还不够)并根据图表执行状态转换。
我对 FRP 没有任何实际经验,但是通过浏览 reactive-banana 的示例,我没有发现 FRP 是否可以解决类似的问题。例如,“两个计数器”示例通过普通if和accumB处理状态。
那么有没有一种干净且声明性的方式来融合 FSA 和 FRP?
QStateMachine框架提供了一种很好的声明方式来定义基于有状态事件的应用程序。即,然后发生一个事件,它执行一个回调(实际上它触发一个信号,但这还不够)并根据图表执行状态转换。
我对 FRP 没有任何实际经验,但是通过浏览 reactive-banana 的示例,我没有发现 FRP 是否可以解决类似的问题。例如,“两个计数器”示例通过普通if和accumB处理状态。
那么有没有一种干净且声明性的方式来融合 FSA 和 FRP?
如果我错过了关于 FSA 的要点,请原谅我,但我相信accumB
和朋友可以很好地和声明性地捕捉你的目标。本质上,单个状态是值,而转换是函数。一个非常简单的例子可能开始于:
data ToggleState = Off | On deriving (Show)
toggle :: ToggleState -> ToggleState
toggle Off = On
toggle On = Off
emergencyShutdown :: ToggleState -> ToggleState
emergencyShutdown _ = Off
(现在我没有什么好主意来捕获类似“开放枚举”的 schtick QState()
,尽管我认为这并不是什么大不了的事,考虑到典型的 Haskeller 对强类型的偏好。)
然后,我们建立 FRP 网络,将状态捕获为行为(即随时间变化的值)并将转换捕获为事件:
-- Assuming eFlipSwitch and ePushShutdownButton are
-- defined terms of user input; say, through
-- bindings to your favourite UI library.
let
eToggle :: Event t (ToggleState -> ToggleState)
eToggle = toggle <$ eFlipSwitch
eShutdown :: Event t (ToggleState -> ToggleState)
eShutdown = emergencyShutdown <$ ePushShutdownButton
-- By defining the behavior, we state once and for all the
-- temporal evolution of the state in terms of the transitions.
bState :: Behavior t ToggleState
bState = accumB Off $ eToggle `union` eShutdown
还有很多其他的可能性。IO
回调可以由事件通过reactimate
. 如 QStateMachine 文档中所述,可以使用filterE
相关的组合器来完成守卫。动画 UI 元素可以很容易地通过绑定模块完成(sink
在 reactive-banana-wx 中查找,或者就此而言,在threepenny-gui 中查找)。等等。