Что не так с моим "событием суммы" в реактивном банане? - PullRequest
8 голосов
/ 12 января 2012

Я изучаю реактивный банан и собираюсь использовать его в приложении на стороне сервера.У меня есть некоторый опыт работы с 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 Ответ

6 голосов
/ 12 января 2012

Ваш диагноз точно верный.Вот два варианта: вы можете вернуться к событию из дискретного через changes, или вы можете создать накапливающиеся события.

Работать в обратном направлении из дискретного, вероятно, проще (и это я бы рекомендовал).Просто сделайте

-- 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')
...