如何在反应香蕉中创建单子行为 [英] How to create monadic behaviour in reactive-banana
问题描述
假设我抓住了按键并相应地操作了代码缓冲区:
Suppose I catch key presses and manipulate a code buffer accordingly:
let
bCode = accumB emptyCode eModifications
eCodeChanges <- changes bCode
我想创建另一个行为bEval
bEval = accumB freshEnv (magic eCodeChanges)
将任何代码状态映射到其评估(仅在真正改变的情况下触发).
which maps any state of code to its evaluation (triggered only when something really changes).
但是,评估是在monad Interpreter
中进行的(从hackage中考虑hint
).我真的可以定义这样的行为bEval
吗?我想我可以将Interpreter String
拖动为行为状态,并累积currentAccumState >>= eval nextEvent
,但是我runInterpreter
在哪里实际强制评估?
However, evaluation happens in a monad Interpreter
(think hint
from hackage). Can I actually define such a behaviour bEval
? I guess I could just drag Interpreter String
as the state in my behaviour, accumulating with currentAccumState >>= eval nextEvent
, but where would I runInterpreter
to actually force the evaluation?
编辑:重要的是,这些动作不仅是IO ()
而是应该修改某些状态.例如,考虑清除缓冲区/重置计数器/在拉链中移动.
Edit: Important thing is that the actions are not merely IO ()
but are supposed to modify some state. Consider for example clearing a buffer/reseting counter/moving around a zipper.
我的主意是:
f :: a -> Maybe (b -> IO b)
mapJustIO :: (a -> Maybe (b -> IO b)) -> Event t a -> Event t (b -> IO b)
mapJustIO f e = filterJust $ f <$> e
accumIO :: a -> Event t (a -> IO a) -> Behaviour t (IO a)
accumIO z e = fold (>>=) (return z) e
我不明白为什么不能有这样的东西.但是,我也看不到如何摆脱IO
的行为:).
I don't see why there could not be something like this. However, I don't see how to get rid of that IO
in the behaviour either :).
为什么IO
在reactive-banana
中实际上不是仅出现在MonadIO
中?
Why aren't IO
occurrences in reactive-banana
actually only MonadIO
?
推荐答案
简而言之,就是像accumB
之类的组合器只能与 pure 函数一起使用.它们无法使用IO monad(或其他类似IO的monad,如Interpreter
)中的函数,因为无法以任何有意义的方式定义操作顺序.
The short answer is that combinators like accumB
and so on can only work with pure functions. They can't work with functions from the IO monad (or another IO-like monad like Interpreter
), because there is no way to define the order of actions in any meaningful way.
要使用IO操作,Reactive.Banana.Frameworks
中的组合器是合适的.例如,您可能想要一个类似
To work with IO actions, the combinators from Reactive.Banana.Frameworks
are appropriate. For instance, you probably want a function like
mapIO' :: (a -> IO b) -> Event a -> MomentIO (Event b)
有关更多信息,请参见上一个答案.
See a previous answer for more on this.
对于hint
中的Interpreter
monad,我建议在主线程中运行它,为您的FRP逻辑分叉一个单独的线程,并使用TVar
s或TChan
进行两者之间的通信. (我将此称为叉车模式).这样,您可以从IO
访问Interpreter
单子.
In the case of the Interpreter
monad from hint
, I recommend running it in the main thread, forking a separate thread for your FRP logic, and using TVar
s or TChan
for communication between the two. (I like to calls this the forklift pattern). This way, you can access the Interpreter
monad from IO
.
这篇关于如何在反应香蕉中创建单子行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!