1

假设我抓住按键并相应地操作代码缓冲区:

let
    bCode = accumB emptyCode eModifications
eCodeChanges <- changes bCode

我想创建另一种行为bEval

bEval = accumB freshEnv (magic eCodeChanges)

它将任何代码状态映射到其评估(仅在某些事情真正发生变化时触发)。

但是,评估发生在单子中Interpreterhint从hackage考虑)。我真的可以定义这样的行为bEval吗?我想我可以Interpreter String在我的行为中拖拽为状态,累积currentAccumState >>= eval nextEvent,但我将在哪里runInterpreter实际强制评估?


编辑:重要的是,这些动作不仅仅是IO ()而且应该修改某些状态。例如,考虑清除缓冲区/重置计数器/在拉链周围移动。

我的想法是这样的:

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情况:)。

为什么不实际IO出现在reactive-bananaonly中MonadIO

4

1 回答 1

1

简短的回答是,诸如此类的组合子accumB只能与函数一起使用。它们不能使用来自 IO monad(或其他类似 IO 的 monad,如Interpreter)的函数,因为无法以任何有意义的方式定义操作的顺序。

要使用 IO 操作,组合子 fromReactive.Banana.Frameworks是合适的。例如,您可能想要一个类似的函数

mapIO' :: (a -> IO b) -> Event a -> MomentIO (Event b)

有关更多信息,请参阅先前的答案

对于Interpreter来自 的 monad hint,我建议在主线程中运行它,为您的 FRP 逻辑分叉一个单独的线程,并使用TVars 或TChan在两者之间进行通信。(我喜欢称之为叉车模式)。这样,您可以InterpreterIO.

于 2015-10-13T09:37:11.400 回答