2012-05-28 1 views
7

J'écris un lecteur de musique dans Haskell avec réactif-banane. Un problème que j'ai est de récupérer des valeurs à jour avec fromPoll. Je veux permettre à l'utilisateur de sélectionner en option une partie de la piste en jouant. Mon code ressemble à ceci:Reactive-banana: les valeurs à jour de fromPoll

makePlayNetworkDescr :: Player a => AddHandler Command -> a -> NetworkDescription t() 
makePlayNetworkDescr addCmdEvent player = do 
    bPosition <- fromPoll (getPosition player) 
    eCmds <- fromAddHandler addCmdEvent 

    let eSetStart = filterE (isJust) $ bPosition <@ filterE (==SetStart) eCmds 
     eSetEnd = filterE (isJust) $ bPosition <@ filterE (==SetEnd) eCmds 
     eClearRange = filterE (==ClearRange) eCmds 

     bStart = accumB Nothing ((const <$> eSetStart) `union` (const Nothing <$ eClearRange)) 
     bEnd = accumB Nothing ((const <$> eSetEnd) `union` (const Nothing <$ eClearRange)) 

Au-dessus, getPosition est une fonction partielle, retour Rien avant la lecture commence réellement. Le problème est qu'une fois que le addCmdEvent se déclenche pour la première fois, bPosition contiendra toujours une valeur Nothing. eSetStart/End calculer leurs valeurs en fonction de cela. Alors seulement bPosition est mis à jour, et c'est la valeur qui sera utilisée la prochaine fois que addCmdEvent déclenche. Et ainsi de suite, la valeur sera toujours "éteint par un", pour ainsi dire.

Il existe un SO question associé, mais dans ce cas il existe un événement "trigger" qui peut être utilisé pour calculer la nouvelle valeur du comportement. Est-ce que quelque chose comme ça est possible avec fromPoll? À partir de réactif-banana-0.5 et 0.6, la fonction fromPoll met à jour le comportement chaque fois qu'un événement externe déclenche le réseau d'événements.

+0

Lorsque vous avez terminé, vous devriez mettre le résultat sur Hackage. Au plaisir de jouer ma musique de Haskell! – amindfv

+0

Je prévois de le mettre sur Hackage une fois (hah) j'ai fini. Cependant, c'est un type de lecteur de musique qui aide à transcrire de la musique, donc je ne suis pas sûr que ce soit intéressant pour d'autres personnes. – oggy

Répondre

2

Vous pouvez accéder à ces mises à jour comme un événement en utilisant

eUpdate <- changes bSomeBehavior 

Cependant, notez que les comportements représentent des valeurs variant dans le temps continu qui ne supportent pas une notion générale d'un « événement de mise à jour ». La fonction changes essayera de renvoyer une approximation utile, mais il n'y a aucune garantie formelle.

Vous pouvez également modifier l'événement externe pour inclure la position du lecteur dans le cadre du addCmdEvent. Dans votre cas, cela signifie ajouter plus de données aux constructeurs SetStart et SetEnd. Ensuite, vous pouvez utiliser

eSetStart = filterJust $ matchSetStart <$> eCmds 
    where 
    matchSetStart (SetStart pos) = Just pos 
    matchSetStart _    = Nothing 

Les deux solutions exigent d'observer la valeur la plus récente comme un événement au lieu d'un comportement. La raison en est que les comportements créés avec stepper renvoient toujours l'ancienne valeur au moment où ils sont mis à jour (ils sont "en retard d'un"), car cela est très utile pour les définitions récursives.

Dans tous les cas, la question sous-jacente est que la position du joueur est mis à jour à l'extérieur bien avant l'addCmdEvent se produit, mais le problème est que ce n'est pas ce que le réseau de l'événement voit. Au contraire, le réseau pense que le comportement renvoyé par fromPoll est mis à jour simultanément avec le addCmdEvent. En fait, à moins d'avoir accès à la source d'événement externe responsable de la mise à jour de la position du joueur, c'est la seule chose à laquelle il peut penser. (Si vous avez accès, vous pouvez utiliser la fonction fromChanges.)

Je me rends compte que ce comportement de fromPoll est peu satisfaisante pour votre cas d'utilisation commune. Je suis indécis si je devrais le réparer dans ma bibliothèque, cependant: il y a un compromis entre fromPoll retournant la dernière valeur et la fonction changes essayant de faire de son mieux.Si la dernière valeur est renvoyée, le changes se comportera comme si elle avait ignoré une mise à jour (lorsque la valeur était mise à jour en externe) et en a déclenché une autre (lorsque le réseau met à jour la valeur pour la rendre externe). Si vous avez une opinion à ce sujet, s'il vous plaît faites le moi savoir.


Notez que la combinaison de comportements avec l'opérateur combinera <*> applicatif les plus récentes valeurs très bien.

+0

Merci pour la réponse. À la fin je suis allé la route de l'interrogation externe des données de position et de l'inclure dans l'événement. En y réfléchissant un peu plus, je ne peux pas vraiment décider s'il y a des avantages conceptuels à obtenir la nouvelle valeur de Poll par rapport à l'obtention d'une source externe, ni l'inverse. D'un autre côté, je ne vois pas le problème de "blocage" de la part de "Poll" tant que la nouvelle valeur n'est pas lue, et seulement l'événement qui a déclenché cette évaluation (en même temps que l'événement changes) beaucoup mieux que moi – oggy

Questions connexes