2013-10-11 74 views
4

比方說,我有過濾重複的事件

x :: Event t (A,B) 

我能得到它的第一個組件:

fst <$> x :: Event t A 

然而,當第一個組件沒有按」這一事件甚至會火改變。我想避免這種情況,因爲這會引發昂貴的重新計算。

AEq一個實例,因此我希望能夠去除連續的比賽時相比,它的最後一個值的第一部分是沒有改變。

理想情況下,我想一個函數

filterDups :: Eq a => Event t a -> Event t a 

這將做到這一點,而不訴諸Moment單子。可能嗎?或者什麼是最好的方式來做到這一點?

回答

2

你必須記住事件的歷史信息來做你想做的事情。正如其他答案已經提到的那樣,您可以使用accumE用於此目的。 Here一個簡潔的定義:

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) 
2

我從來沒有使用反應香蕉,並沒有測試過,所以要小心。儘管如此,至少在類型分析中還是有一個想法。我們將使用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) 
2

該解決方案使用(或濫用)的事實stepper功能更新Behavior「稍微之後的」 Eventsee the comment in the docs

首先創建一個基於Event一個Behavior,你必須找到對您的解決方案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 

使用看看這個gist一個簡單的例子。

+1

這個實現是在精神上是正確的,但在事件同時包含事件發生了微妙的問題。該行爲只會記住同時發生的最後一個值,而不會記錄中間的值。一個完全正確的實現將在這裏使用'accumE'。然而,未來版本的反應型香蕉將完全擺脫同時發生的事件,因此這裏的定義再次變得正確。 –

+0

感謝您的澄清,這是我第一次使用反應香蕉,我不確定這種解決方案是否適用於所有情況。 –