2012-05-28 6 views
7

Ich schreibe einen Musik-Player in Haskell mit reactive-banana. Ein Problem, das ich habe, ist, aktuelle Werte mit fromPoll abzurufen. Ich möchte dem Benutzer ermöglichen, optional einen Teil der Spur während der Wiedergabe auszuwählen. Mein Code sieht in etwa wie folgt aus:Reactive-Banane: aktuelle Werte von 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)) 

Oben, getPosition ist eine Teilfunktion, Rückkehr Nichts, bevor die Wiedergabe tatsächlich beginnt. Das Problem ist, dass, sobald die addCmdEvent Feuer zum ersten Mal, bPosition werden immer noch einen Nichts Wert halten. eSetStart/Ende berechnen Sie ihre Werte auf dieser Grundlage. Nur dann wird bPosition aktualisiert, und dies ist der Wert, der beim nächsten Mal verwendet wird, das addCmdEvent ausgelöst wird. Und so weiter, der Wert wird sozusagen immer "um eins" sein.

Es gibt eine verwandte SO question, aber in diesem Fall gibt es ein "Trigger" -Ereignis, das verwendet werden kann, um den neuen Wert des Verhaltens zu berechnen. Ist so etwas mit fromPoll möglich?

+0

Wenn Sie fertig sind, sollten Sie das Ergebnis auf Hackage setzen. Ich freue mich darauf, meine Musik von Haskell zu spielen! – amindfv

+0

Ich plane, es einmal auf Hackage zu setzen (hah) Ich bin fertig. Es ist jedoch ein "Scratch My Eitch" Art von Musik-Player, um mit Transkribieren von Musik zu helfen, so dass ich nicht sicher bin, wie interessant es für andere Menschen wäre. – oggy

Antwort

2

Ab reaktiv-banana-0.5 und 0.6 aktualisiert die fromPoll-Funktion das Verhalten jedes Mal, wenn ein externes Ereignis das Ereignisnetzwerk auslöst. Sie können diesen Updates als Ereignis zugreifen, indem

eUpdate <- changes bSomeBehavior 

jedoch verwenden, beachten Sie, dass Verhaltensweisen kontinuierliche zeitlich veränderlichen Werte darstellen, die keinen allgemeinen Begriff eines „Aktualisierungsereignisses“ unterstützen. Die changes Funktion wird versuchen, eine nützliche Annäherung zurückzugeben, aber es gibt keine formalen Garantien.

Alternativ können Sie das externe Ereignis so ändern, dass die Playerposition als Teil der addCmdEvent enthalten ist. In Ihrem Fall bedeutet dies, dass Sie den Konstruktoren SetStart und SetEnd mehr Daten hinzufügen. Dann können Sie

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

verwenden Beide Lösungen benötigen Sie den aktuellsten Wert als ein Ereignis zu beobachten, statt eines Verhaltens. Der Grund dafür ist, dass mit stepper erstellte Verhaltensweisen immer den alten Wert zum Zeitpunkt ihrer Aktualisierung zurückgeben (sie "liegen um eins zurück"), da dies sehr nützlich für rekursive Definitionen ist.

In jedem Fall ist das zugrunde liegende Problem ist, dass der Spieler Position extern lange aktualisiert wird, bevor die addCmdEvent auftritt, aber das Problem ist, dass dies nicht das, was das Event-Netzwerk sieht, ist. Das Netzwerk denkt vielmehr, dass das von fromPoll zurückgegebene Verhalten gleichzeitig mit dem addCmdEvent aktualisiert wird. In der Tat, es sei denn, Sie haben Zugriff auf die externe Ereignisquelle, die für die Aktualisierung der Player-Position verantwortlich ist, das ist das einzige, was es denken kann. (Wenn Sie Zugriff haben, können Sie die fromChanges Funktion verwenden.)

Ich weiß, dass dieses Verhalten von fromPoll ist etwas unbefriedigend für Ihren allgemeinen Anwendungsfall. Ich bin unschlüssig, ob ich es in meiner Bibliothek reparieren sollte: Es gibt einen Kompromiss zwischen fromPoll, der den letzten Wert zurückgibt, und der changes-Funktion, die versucht, ihr Bestes zu geben.Wenn der letzte Wert zurückgegeben wird, verhält sich die changes so, als ob sie eine Aktualisierung übersprungen hat (wenn der Wert extern aktualisiert wurde) und eine überflüssige ausgelöst hat (wenn das Netzwerk den Wert aktualisiert, um mit der externen übereinzustimmen). Wenn Sie dazu eine Meinung haben, lassen Sie es mich bitte wissen.


Beachten Sie, dass Verhaltensweisen, die mit dem applicative Operator kombiniert <*> werden die neuesten Werte ganz gut kombinieren.

+0

Danke für die Antwort. Am Ende ging ich den Weg, die Positionsdaten extern abzufragen und in das Event aufzunehmen. Wenn ich darüber nachdenke, kann ich nicht wirklich entscheiden, ob es irgendwelche konzeptuellen Vorteile gibt, wenn man den frischen Wert von fromPoll bekommt, im Vergleich dazu, es von einer externen Quelle zu bekommen, noch umgekehrt. Auf der anderen Seite bekomme ich nicht das Problem von "Blockieren" von "Poll", bis der neue Wert gelesen wird, und erst dann das Ereignis auslösen, das diese Auswertung ausgelöst hat (gleichzeitig mit dem Ereignis changes), aber Sie kennen Ihre Bibliothek viel besser als ich – oggy

Verwandte Themen