2013-11-27 2 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 получает впрыскивается в список. Эффективно, каждый раз, когда вводится нажатие, я ожидаю, что все числа в списке будут увеличиваться на единицу. Вместо этого числа увеличиваются только после того, как я нажимаю пробел. Кто-нибудь знает, где я ошибаюсь?

ответ

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 

Это гарантирует, что при возникновении какого-либо события они получат самую свежую версию списка.

Смежные вопросы