2

我现在正在通过 FieldTrip 适配器学习 FRP。并以奇怪的帧调度和集成方式解决了这个问题。所以现在我正在尝试构建自己的标记事件来对齐行为步进。

所以...

flipflop :: Behavior String
flipflop = stepper "none" (xflip 2) where
    xflip t0 = do
        t <- withTimeE_ (atTime t0)
        return "flip" `mplus` xflop (t+3)
    xflop t0 = do
        t <- withTimeE_ (atTime t0)
        return "flop" `mplus` xflip (t+2)
txtGeom = ((uscale2 (0.5::Float) *%) . utext . show <$>)
main = anim2 (txtGeom . pure flipflop)

问题是:

  • 为什么这个例子会导致内存泄漏?
  • 是否有安全的方法来构建事件序列,其中每个下一个事件都根据前一个进行安排?
  • 4

    1 回答 1

    1

    看起来以这种方式加入活动是行不通的。试试这个:

    import FRP.Reactive
    import FRP.Reactive.FieldTrip
    import Graphics.FieldTrip
    import Control.Monad
    import Control.Applicative
    
    
    flipflop = stepper "none" $ either (const "flip") (const "flop")
                <$> eitherE (atTimes ((+2) <$> [0,5..])) (atTimes [5,10..])
    
    txtGeom = ((uscale2 (0.5::Float) *%) . utext . show <$>)
    main = anim2 (txtGeom . pure flipflop)
    

    不幸的是,这个版本仍然存在空间泄漏,但要小得多。运行大约一分钟后,总 RAM 使用量约为 9.7MB。

    还有一个flipFlop创建Behavior Bool. 这对于触发器来说效果很好,但我没有看到在前两秒添加“none”的干净方法。

    我也试过这个

    flipflop = stepper "none" $ (const "flip" <$> (atTimes ((+2) <$> [0,5..])))
                                `mplus` (const "flop" <$> atTimes [5,10..])
    

    这似乎与第一个版本相同。

    当然,这对于以您询问的方式进行动态调度并没有多大作用。不幸的是,我不相信这个用例在 Reactive 中有效。

    我非常欣赏制作 Reactive 的作品,我想喜欢它,但它似乎非常难以推理。 邮件列表中的这个线程是似乎很常见的问题(和解决方案!)的一个例子。此外,“unamb”库(它是 Reactive 的基础)暴露了 GHC 线程中的一些非常微妙的错误,这些错误对结果造成了严重破坏,直到它们在 ghc-6.12 周围得到修复。尽管这绝不是 Conal 或其他 Reactive 贡献者的错,但它使框架的使用变得更加困难,尤其是在早期的 GHC 中。

    您可以尝试其他一些 FRP 包。Yampa 有一个很好的实现,我听说Elerea比较容易上手,而且它有一个很好的演示应用程序

    于 2011-01-08T04:47:31.780 回答