【问题标题】:How to create monadic behaviour in reactive-banana如何在反应香蕉中创建一元行为
【发布时间】:2015-10-12 18:55:57
【问题描述】:

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

let
    bCode = accumB emptyCode eModifications
eCodeChanges <- changes bCode

我想创建另一个行为bEval

bEval = accumB freshEnv (magic eCodeChanges)

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

但是,评估发生在 monad Interpreter 中(想想来自 hackage 的 hint)。我真的可以定义这样的行为bEval吗?我想我可以将Interpreter String 拖到我行为中的状态,与currentAccumState &gt;&gt;= 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-banana 实际上只有MonadIO

【问题讨论】:

    标签: monads reactive-banana


    【解决方案1】:

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

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

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

    请参阅previous answer 了解更多信息。

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

    【讨论】:

    • 我从来没有在函数式​​语言中做过任何关于并发的事情,更不用说 Haskell,链接看起来很有趣,我喜欢你的博客。问你是否知道一些很好的全面但易于理解的关于你的叉车博客文章所基于的问题的介绍是否太过分了?不管怎样,谢谢你的指点。
    • 还有一个更深层的原因是为什么不分叉就不可能做到这一点?您的叉车库的状态如何?顺便说一句,两个链接都指向同一篇文章,这是故意的吗?
    • @jd823592 哎呀,对相同的链接感到抱歉,第一个链接应该去完全不同的地方。
    • @jd823592 关于Haskell并发编程的介绍,我推荐"Tackling the awkward squad""Parallel and concurrent programming in Haskell"
    • 谢谢!究竟是什么阻止行为折叠任意 monad(在我的例子中是 Interpreter)?
    猜你喜欢
    • 1970-01-01
    • 2011-09-25
    • 2015-01-28
    • 2017-11-22
    • 1970-01-01
    • 2013-06-16
    • 1970-01-01
    • 2013-06-20
    • 1970-01-01
    相关资源
    最近更新 更多