2013-11-27 56 views
1

所以我想了解鈉的功能反應式編程模型如何工作,我遇到了一些障礙。 我有一個數值列表,我使用類似值的「時間」進行更新,並且在傳入空格字符時將此列表添加到此列表中。 運行此操作的引擎如下所示。鈉事件更新沒有反映

import FRP.Sodium 

type Time = Event Int 
type Key = Event Char 
type Game a = Time -> Key -> Reactive (Behavior a) 

run :: Show a => Game a -> IO() 
run game = do 
    (dtEv, dtSink) <- sync newEvent 
    (keyEv, keySink) <- sync newEvent 
    g <- sync $ do 

     game' <- game dtEv keyEv 
     return game' 

    go g dtSink keySink 
    return() 
    where 
    go gameB dtSink keySink = do 
     sync $ dtSink 1 

     ks <- getLine 
     mapM_ (sync . keySink) ks 

     v <- sync $ sample gameB 
     print v 

     go gameB dtSink keySink 

因此,我打印遊戲行爲給出的每個「打勾」的當前值。這是遊戲行爲的代碼。

main :: IO() 
main = run game 


game :: Time -> Key -> Reactive (Behavior [Int]) 
game dt key = do 
    let spawn = const 0 <$> filterE (==' ') key 

    rec 
     bs <- hold [] $ snapshotWith (\s xs -> (s:xs)) spawn updated 

     updated <- hold [] $ snapshotWith (\t xs -> map (+t) xs) dt bs 


    return updated 

什麼,我期望這做的是與輸入的每一個空格字符,一個0被注入到列表中。 實際上,每次按下Enter鍵時,我都希望列表中的所有數字都增加1。 取而代之的是,只有按下空格鍵後,數字纔會增加。 有誰知道我要去哪裏錯了?

回答

1

經過一番思考之後,很明顯是什麼問題。 我的代碼的問題是,我有這種循環依賴,沒有考慮到每個行爲也取決於它自己的變化的事實。 這意味着每當我嘗試添加東西到列表中時,它都會將時間更新給出的列表的舊值更改爲值,直到時間值更改。 爲了糾正這個問題,我重構了game行爲來合併更新和產生事件,如下所示。

data GEvent = Alter ([Int] -> [Int]) 

game :: Time -> Key -> Reactive (Behavior [Int]) 
game dt key = do 
    let spawn = const (Alter (\xs -> (0:xs))) <$> filterE (==' ') key 
     update = (\t -> Alter (\xs -> map (+t) xs)) <$> dt 
     applyAlter (Alter f) xs = f xs 

    rec 
     bs <- hold [] $ snapshotWith applyAlter (merge spawn update) bs 


    return bs 

這可以確保當發生任何事件時它們獲得最新的列表版本。

相關問題