Reactive-banana:来自fromPoll的最新值

ogg*_*ggy 7 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))
Run Code Online (Sandbox Code Playgroud)

上面,getPosition是一个部分函数,在播放实际开始之前返回Nothing.问题是,一旦addCmdEvent第一次触发,bPosition仍将保持Nothing值.eSetStart/End基于此计算它们的值.只有这样才能更新bPosition,这是下次addCmdEvent触发时将使用的值.依此类推,价值总是"一个一个",可以这么说.

存在相关的SO问题,但在这种情况下存在"触发"事件,其可用于计算行为的新值.fromPoll有什么可能吗?

Hei*_*mus 2

从reactive-banana-0.5和0.6开始,fromPoll只要外部事件触发事件网络,该函数就会更新行为。您可以使用以下方式将这些更新作为事件访问

eUpdate <- changes bSomeBehavior
Run Code Online (Sandbox Code Playgroud)

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

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

eSetStart = filterJust $ matchSetStart <$> eCmds
    where
    matchSetStart (SetStart pos) = Just pos
    matchSetStart _              = Nothing
Run Code Online (Sandbox Code Playgroud)

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

无论如何,根本问题是玩家位置早在addCmdEvent事件发生之前就已从外部更新,但问题是这不是事件网络看到的。相反,网络认为更新返回的行为fromPolladdCmdEvent. 事实上,除非您有权访问负责更新玩家位置的外部事件源,否则这是它唯一能想到的事情。(如果您有访问权限,则可以使用该fromChanges功能。)

我意识到这种行为fromPoll对于您的常见用例来说有些不令人满意。fromPoll不过,我尚未决定是否应该在我的库中修复它:返回最新值和changes尝试做到最好的函数之间存在权衡。如果返回最新值,则其changes行为就像跳过了一次更新(当该值在外部更新时)并触发了一个多余的更新(当网络更新该值以匹配外部更新时)。如果您对此有任何意见,请告诉我。


请注意,将行为与应用运算符组合<*>将很好地组合最新的值。