在反应香蕉中执行单个开关

och*_*les 6 haskell reactive-banana

我正在构建一个多模态编辑器reactive-banana- 并且在大多数情况下它是完美的.为了扩展我的场景,编辑器是一些映射软件,或者您可以将其视为一个非常简单的矢量图形编辑器.它目前有两种状态 - 选择模式多边形创建模式.在选择模式下,用户可以使用鼠标右键选择以前创建的多边形(理论上可以将您带到新选择的模式),也可以使用鼠标左键开始创建新的多边形.

目的是,当按下鼠标左键时,我们从选择模式切换到多边形创建模式.在此模式下,鼠标左键表示"添加新顶点",直到用户返回到原始顶点.此时,它们已关闭多边形,因此我们返回选择模式.

我已经实现了几种不同的方式,最近注意到事件切换几乎使这个非常优雅.我可以有:

defaultMode :: Frameworks t => HadoomGUI -> Moment t (Behavior t Diagram)
defaultMode gui@HadoomGUI{..} =
  do mouseMoved <- registerMotionNotify guiMap
     mouseClicked <- registerMouseClicked guiMap
     let lmbClicked = ...
         gridCoords = ...
         diagram = ... 
     switchToCreateSector <- execute ((\m ->
                                         FrameworksMoment
                                           (=<< trimB =<< createSectorMode gui emptySectorBuilder m)) <$>
                                      (gridCoords <@ lmbClicked))
     return (switchB diagram switchToCreateSector)
Run Code Online (Sandbox Code Playgroud)

随着

createSectorMode :: Frameworks t
                 => HadoomGUI
                 -> SectorBuilder
                 -> Point V2 Double
                 -> Moment t (Behavior t Diagram)
createSectorMode HadoomGUI{..} initialSectorBuilder firstVertex =
  do mouseClicked <- registerMouseClicked guiMap
     ...
Run Code Online (Sandbox Code Playgroud)

这当然有效 - 只需单击一下鼠标.如果我单击地图一次,我将从我刚刚进入的状态切换到扇区创建模式.但是,如果我再次单击,defaultMode接收单击事件并切换到新的多边形创建模式,抛弃我以前的状态.

我想做的是切换defaultMode一次,永远不可能回来.基本上我想把Behavior t Diagram生产的"交换" defaultMode与结果createSectorMode.

我理解reactive-banana动态事件的垃圾收集存在问题,但我现在愿意接受它.上面的公式比我到目前为止所写的任何其他公式都要精确得多 - 比如有一个CurrentState变量并根据其中的内容过滤各种事件.我遇到的问题是它太大了,给我留下了太大的空间.通过切换,我只能参与我可以进行的事件.

Hei*_*mus 4

这个问题有点开放性,所以我无法给出明确的答案。但我当然可以发表我的意见。;-)

然而,我可能会做的是将模式之间的切换与模式内的行为分开。如果我们暂时忘记 FRP,您的程序看起来有点像一对递归调用自身的函数:

defaultMode = ... `andthen` sectorMode
sectorMode  = ... `andthen` defaultMode
Run Code Online (Sandbox Code Playgroud)

它的写法有点像“顺序”程序,“首先执行此模式,然后执行该模式”。我认为这没有什么问题,尽管默认的 APIreactive-banana 尤其switchB不能很好地支持这种风格。你(私下)提到你可以写一个

once :: Event t a -> Event t a
Run Code Online (Sandbox Code Playgroud)

组合器允许事件第一次发生,但丢弃其余事件。这确实是顺序风格所需要的。

不过,由于您总是返回默认模式,因此我可能会尝试不同的方法,其中每种模式都有一个事件表明它想要切换出去。切换本身由“外部”实体负责。这个想法是为了避免上面程序中某些高阶组合器的显式递归。在伪代码中,这看起来像这样:

modeManager = switchB initialMode changeMode
changeMode  = defaultModeSwitch `union` sectorModeSwitch
Run Code Online (Sandbox Code Playgroud)

虽然我对细节有点不确定。事实上,我不完全确定它是否有效,您可能仍然需要once组合器。

无论如何,这只是如何进行切换的一个想法。我完全同意切换是处理不同模式的正确方法。