Фильтр повторяющихся событий в реактивном банане

Допустим, у меня есть

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.

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