Фильтр повторяющихся событий в реактивном банане
Допустим, у меня есть
x :: Event t (A,B)
Я могу получить первый компонент этого:
fst <$> x :: Event t A
Однако это событие будет запущено, даже если первый компонент не изменится. Я хочу избежать этого, потому что это вызовет дорогостоящее пересчет.
A
это пример Eq
, поэтому я хочу иметь возможность удалять последовательные события, когда первый компонент не изменился по сравнению с его последним значением.
В идеале я бы хотел функцию
filterDups :: Eq a => Event t a -> Event t a
который сделал бы это, не прибегая к Moment
монада. Является ли это возможным? Или какой лучший способ сделать это?
3 ответа
Вы должны запомнить информацию об истории события, чтобы делать то, что вы хотите. Как уже упоминались другие ответы, вы можете использовать accumE
для этой цели. Вот краткое определение:
unique :: Eq a => Event t a -> Event t a
unique = filterJust . accumE Nothing
. fmap (\a acc -> if Just a == acc then Nothing else Just a)
Я никогда не использовал реактивный банан и не проверял это, так что будьте осторожны. Тем не менее, вот одна идея, по крайней мере, проверки типов. Мы будем использовать accumE
вспомнить кое-что о прошлых событиях.
notice x (old, new) = (new, Just x)
changed (Just old, Just new) = guard (old /= new) >> return new
changed (_, new) = new
justChanges :: Eq a => Event t a -> Event t a
justChanges e = filterJust $ changed <$> accumE (Nothing, Nothing) (notice <$> e)
Это решение использует (или злоупотребляет) тот факт, что stepper
функция обновляет Behavior
"немного после" Event
см. комментарий в документации.
Сначала создайте Behavior
на основе Event
, вы должны найти подходящее первое значение для Behavior
в вашем решении, для простоты я предполагаю, что первый элемент вашей пары Int
:
x :: Event t (Int, b)
firstB :: Behavior t Int
firstB = stepper 0 $ fst <$> x
Тогда вы можете использовать filterApply
функция:
filterDups e = filterApply (firstNotEq <$> firstB) e
where firstNotEq old (new, _) = new /= old
firstB = stepper 0 $ fst <$> e
Взгляните на эту суть для простого примера использования графического интерфейса Threepenny.