Reactive-banana:来自fromPoll的最新值

时间:2012-05-28 16:44:48

标签: haskell frp reactive-banana

我正在Haskell写一个带有反应性香蕉的音乐播放器。我遇到的一个问题是使用fromPoll获取最新值。我想让用户可以选择在播放时选择音轨的一部分。我的代码看起来像这样:

makePlayNetworkDescr :: Player a => AddHandler Command -> a -> NetworkDescription t ()
makePlayNetworkDescr addCmdEvent player = do
    bPosition <- fromPoll (getPosition player)
    eCmds <- fromAddHandler addCmdEvent

    let eSetStart = filterE (isJust) $ bPosition <@ filterE (==SetStart) eCmds
        eSetEnd = filterE (isJust) $ bPosition <@ filterE (==SetEnd) eCmds
        eClearRange = filterE (==ClearRange) eCmds

        bStart = accumB Nothing ((const <$> eSetStart) `union` (const Nothing <$ eClearRange))
        bEnd = accumB Nothing ((const <$> eSetEnd) `union` (const Nothing <$ eClearRange))

上面, getPosition 是一个部分函数,​​在播放实际开始之前返回 Nothing 。问题是,一旦 addCmdEvent 首次触发, bPosition 仍会保留 Nothing 值。 eSetStart / End 根据此计算其值。只有这样才能更新 bPosition ,这是下次 addCmdEvent 触发时将使用的值。依此类推,价值总是“一个一个”,可以这么说。

有一个相关的SO question,但在这种情况下,存在一个“触发器”事件,可用于计算行为的新值。 fromPoll有什么可能吗?

1 个答案:

答案 0 :(得分:2)

从reactive-banana-0.5和0.6开始,只要外部事件触发事件网络,fromPoll函数就会更新行为。您可以使用

将这些更新作为事件进行访问
eUpdate <- changes bSomeBehavior

但是,请注意,行为表示连续的时变值,这些值不支持“更新事件”的一般概念。 changes函数将尝试返回有用的近似值,但没有正式的保证。

或者,您可以更改外部事件以将玩家位置包含在addCmdEvent中。在您的情况下,这意味着向SetStartSetEnd构造函数添加更多数据。然后,您可以使用

eSetStart = filterJust $ matchSetStart <$> eCmds
    where
    matchSetStart (SetStart pos) = Just pos
    matchSetStart _              = Nothing

这两种解决方案都要求您将最近的值视为事件而不是行为。原因是使用stepper创建的行为将始终在更新时返回旧值(它们“落后于1”),因为这对递归定义非常有用。

在任何情况下,潜在问题是玩家位置在addCmdEvent发生之前很久就在外部更新,但问题是这不是事件网络看到的。相反,网络认为fromPoll返回的行为与addCmdEvent同时更新。事实上,除非您有权访问负责更新玩家位置的外部事件源,否则这是唯一可以思考的事情。 (如果您有权访问,则可以使用fromChanges功能。)

我意识到fromPoll的这种行为对于您的常见用例来说有些不尽如人意。我不确定是否应该在我的库中修复它:在fromPoll返回最新值和changes函数之间需要权衡以确保最佳状态。如果返回最新值,则changes的行为就好像它已跳过一次更新(当值在外部更新时)并触发多余的值(当网络更新值以匹配外部值时)。如果您对此有任何意见,请告诉我。


请注意,将行为与应用运算符<*>相结合,可以合并最近的值。