Reactive-banana: актуальные значения от fromPoll
Я пишу музыкальный проигрыватель на 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 является частичной функцией, которая ничего не возвращает до того, как воспроизведение фактически начнется. Проблема в том, что после первого запуска addCmdEvent bPosition будет по-прежнему содержать значение Nothing. eSetStart / End рассчитать их значения на основе этого. Только тогда bPosition обновляется, и это значение будет использоваться в следующий раз, когда сработает addCmdEvent. И так далее, значение, так сказать, всегда будет "выключено одним".
Есть связанный вопрос SO, но в этом случае существует событие "триггера", которое можно использовать для вычисления нового значения поведения. Что-нибудь подобное возможно с fromPoll?
1 ответ
По реактивному банану-0,5 и 0,6 г. fromPoll
функция обновляет поведение всякий раз, когда внешнее событие запускает сеть событий. Вы можете получить доступ к этим обновлениям как к событию, используя
eUpdate <- changes bSomeBehavior
Тем не менее, обратите внимание, что поведение представляет собой непрерывные изменяющиеся во времени значения, которые не поддерживают общее понятие "событие обновления". changes
Функция попытается вернуть полезное приближение, но формальных гарантий нет.
Кроме того, вы можете изменить внешнее событие, включив в него позицию игрока как часть addCmdEvent
, В вашем случае это означает добавление дополнительных данных в SetStart
а также SetEnd
Конструкторы. Затем вы можете использовать
eSetStart = filterJust $ matchSetStart <$> eCmds
where
matchSetStart (SetStart pos) = Just pos
matchSetStart _ = Nothing
Оба решения требуют, чтобы вы наблюдали самое последнее значение как событие, а не как поведение. Причина в том, что поведение, созданное с stepper
всегда будет возвращать старое значение в тот момент, когда они обновляются (они "отстают на единицу"), так как это очень полезно для рекурсивных определений.
В любом случае, основная проблема заключается в том, что позиция игрока обновляется внешне задолго до addCmdEvent
происходит, но проблема в том, что это не то, что видит сеть событий. Скорее, сеть считает, что поведение возвращается fromPoll
обновляется одновременно с addCmdEvent
, Фактически, если у вас нет доступа к внешнему источнику событий, который отвечает за обновление позиции игрока, это единственное, о чем он может думать. (Если у вас есть доступ, вы можете использовать fromChanges
функция).
Я понимаю, что это поведение fromPoll
является несколько неудовлетворительным для вашего общего случая использования. Я не знаю, следует ли мне исправить это в моей библиотеке, хотя: есть компромисс между fromPoll
возвращая последнее значение и changes
Функция пытается сделать все возможное. Если возвращается последнее значение, то changes
будет вести себя так, как если бы он пропустил одно обновление (когда значение было обновлено извне) и вызвало лишнее (когда сеть обновляет значение, чтобы оно соответствовало внешнему). Если у вас есть мнение по этому поводу, пожалуйста, дайте мне знать.
Обратите внимание, что сочетание поведения с аппликативным оператором <*>
будет прекрасно сочетать самые последние значения.