2012-01-11 69 views
8

我正在學習反應式香蕉,並打算在服務器端應用程序中使用它。我在RxJs有一些背景,所以我習慣於將事件與不同的組合器結合在一起。所以我從簡單的事件組合器例子開始。我試圖製作一個簡單的反應式香蕉示例,將兩個整型事件組合成一個總和事件。我明白爲了能夠結合來自不同事件的價值觀,我必須首先將它們變爲行爲,組合並最終將其變爲新事件。這是我的做法:反應香蕉中的「總和事件」有什麼問題?

-- 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)中出現新值時正確觸發,但它包含陳舊值。這顯然是由於步進器的工作原理(行爲的價值在事件發生後略有改變)。我嘗試用Discrete替換行爲,結果相同。

有沒有簡單的方法來使這種事件組合器正常工作?

回答

6

您的診斷是完全正確的。以下是兩個選項:您可以通過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永遠當e1e2變化更新。

該替代方案只使用事件,將傳入的事件轉換爲累積函數。這聽起來很複雜,但代碼非常簡單。

--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') 
+0

只是爲了澄清:任何一種方法都沒有延遲,'sumE'事件將與'e1'和'e2'同時發生。 – 2012-01-12 15:13:12

+0

謝謝,@ HeinrichApfelmus。我編輯了我的答案,希望更清楚。 – 2012-01-12 15:57:59

+0

謝謝你們!它現在有效。 – raimohanska 2012-01-13 17:53:58