Что не так с моим "событием суммы" в реактивном банане?
Я изучаю реактивный банан и собираюсь использовать его в приложении на стороне сервера. У меня есть некоторый опыт работы с RxJ, поэтому я привык комбинировать события с разными комбинаторами. Итак, я начал с простых примеров комбинатора событий. Я попытался сделать простой пример реактивного банана, который бы объединил два целочисленных события в событие суммы. Я понимаю, что для того, чтобы объединить значения из разных событий, я должен сначала превратить их в Поведения, затем выполнить комбинацию и, наконец, превратить это в новое событие. Вот как я это сделал:
-- Behaviors from Events e1, e2
let b1 = stepper 0 e1 :: Behavior Int
let b2 = stepper 0 e2 :: Behavior Int
-- Sum Behavior
let sumB = (+) <$> b1 <*> b2
-- Back to Event
let sumE = sumB <@ (e1 `union` e2)
Полный пример запуска можно найти в Gist 1594917.
Проблема здесь заключается в том, что хотя событие sumE правильно запускается, когда в одном из событий (e1, e2) появляется новое значение, оно содержит устаревшее значение. Это, по-видимому, связано с тем, как работает степпер (значение поведения меняется "незначительно после" возникновения события). Я попытался заменить Поведение на Дискретное, с тем же результатом.
Есть ли простой способ заставить этот вид комбинаторов событий работать правильно?
1 ответ
Ваш диагноз точно верный. Вот два варианта: вы можете вернуться к событию с дискретного через changes
Или вы можете создавать накапливающиеся события.
Работать с Discrete, вероятно, проще (и я бы порекомендовал). Просто делать
-- Discretes from Events e1, e2
let d1 = stepperD 0 e1 :: Discrete Int
let d2 = stepperD 0 e2 :: Discrete Int
-- Sum Discrete
let sumD = (+) <$> d1 <*> d2
-- Back to Event
let sumE = changes sumD
Сейчас sumE
всегда будет обновляться, когда e1
или же e2
изменения.
Альтернатива использует только События, преобразовывая входящие события в функции накопления. Звучит сложно, но код довольно прост.
--convert each input into an accumulating tuple
let e1' = (\l (_,r) -> (l,r)) <$> e1
let e2' = (\r (l,_) -> (l,r)) <$> e2
let sumE = uncurry (+) <$> accumE (0,0) (e1' `union` e2')