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 будет вести себя так, как если бы он пропустил одно обновление (когда значение было обновлено извне) и вызвало лишнее (когда сеть обновляет значение, чтобы оно соответствовало внешнему). Если у вас есть мнение по этому поводу, пожалуйста, дайте мне знать.


Обратите внимание, что сочетание поведения с аппликативным оператором <*> будет прекрасно сочетать самые последние значения.

Другие вопросы по тегам