钠赛事更新未得到反映

时间:2013-11-27 02:04:58

标签: haskell frp

所以我试图了解Sodium的功能反应式编程模型是如何工作的,而且我遇到了一些障碍。 我有一个数字列表,我正在使用“时间”值更新,并且当传入空格字符时,我将添加到此列表中。 运行它的引擎如下。

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 个答案:

答案 0 :(得分: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

这可确保在任何一个事件发生时,他们获得最新版本的列表。