基于我之前的问题,我的设置逐渐完善(How to create monadic behaviour in reactive-banana):
假设存在eKey
,按下某个键时会触发一个事件,b
类型Buffer
,只要在eKey
中发生支持的事件,就会对其进行适当修改,并且最后,对某些事件采取IO
次行动。这些IO
操作取决于b
的状态(为简单起见,假设它们将{{1}}的当前状态打印到控制台。)
目前,我有这个选择在事件中发生的操作:
b
然后我做:
getKeyAction :: KeyVal -> Maybe (IO Buffer -> IO Buffer)
getKeyAction 65288 = Just . liftM $ backspace
getKeyAction 65293 = Just $ \mb -> do
b <- mb
print $ "PRESSED ENTER: " ++ toString b
return emptyBuffer
getKeyAction 65360 = Just . liftM $ leftMost
getKeyAction 65361 = Just . liftM $ left
...
getKeyAction _ = Nothing
某些let
eBufferActions = filterJust $ getKeyAction <$> eKey
bBuffer = accumB (return emptyBuffer) eBufferActions -- model `b`
eBuffer <- changes bBuffer
reactimate' $ fmap displayBuffer <$> eBuffer
。
它似乎没有按预期工作。 displayBuffer :: IO Buffer -> IO ()
的状态似乎每次重新评估每个事件(每次事件发生时有效地运行到目前为止收集的所有bBuffer
个动作),这在我回想起来时是有意义的。
我应该如何重构代码才能正确执行此操作? (即IO
个动作查看缓冲区的当前状态,除了缓冲区之外什么都没有累积)
如果我可以在适当的IO
事件中构建一个值Event
的{{1}},那么我可以简单地将我的bBuffer
行动映射到它和eKey
。你怎么看?怎么做? IO
会实现我想做的事吗?但是,如果我使用reactimate
快照<@
以将b
映射到其上,我将如何将当前更改推迟到与当前按键相关联的b
?
答案 0 :(得分:1)
好的,所以我相信这解决了我的问题,但我不确定这是正确的做法。所以请评论。
IO
(return
除外)eKey
事件过滤为两个:eBuffer
和eConfirm
eBuffer
收集所有修改事件(包括在确认时清除缓冲区)eConfirm
收集所有确认事件eConfirm
标记bBuffer
,用于捕获缓冲区的演变reactimate
分别为缓冲区的IO
和changes
代码片段:
getKeyAction :: KeyVal -> Maybe (Buffer -> Buffer)
getKeyAction 65288 = Just backspace
-- omit action for ENTER
...
getConfirm :: KeyVal -> Maybe (Buffer -> Buffer)
getConfirm 65293 = Just (const mkBuffer) -- Clear buffer on ENTER
getConfirm _ = Nothing
然后在网络描述中:
let
eBuffer = filterJust $ getKeyAction <$> eKey
eConfirm = filterJust $ getConfirm <$> eKey
bBuffer = accumB mkBuffer $ unions [ eBuffer, eConfirm ]
eEval = bBuffer <@ eConfirm
eBufferChanges <- changes bBuffer
reactimate $ evalBuffer <$> eEval
reactimate' $ fmap displayBuffer <$> eBufferChanges
代表evalBuffer :: Buffer -> IO ()
和displayBuffer :: Buffer -> IO ()
。