2012-05-28 10 views
7

Escribo un reproductor de música en Haskell con plátano reactivo. Un problema que tengo es obtener valores actualizados con fromPoll. Quiero permitir que el usuario seleccione opcionalmente una parte de la pista mientras juega. Mi código es como la siguiente:Reactive-banana: valores actualizados desde 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)) 

arriba, getPosition es una función parcial, volviendo Nada antes de la reproducción comienza en realidad. El problema es que una vez que el addCmdEvent se dispara por primera vez, bPosition seguirá teniendo un valor Nothing. eSetStart/End calcule sus valores según esto. Solo entonces se actualiza bPosition, y este es el valor que se utilizará la próxima vez que addCmdEvent incendios. Y así sucesivamente, el valor siempre será "off by one", por así decirlo.

Hay un SO question relacionado, pero en ese caso existe un evento "desencadenante" que se puede usar para calcular el nuevo valor del comportamiento. ¿Hay algo como eso con fromPoll?

+0

Cuando hayas terminado, deberías poner el resultado en Hackage. ¡Espero poder escuchar mi música de Haskell! – amindfv

+0

Planeo ponerlo en Hackage una vez (hah) he terminado. Sin embargo, es un tipo de reproductor de música "scratch my own itch" para ayudar con la transcripción de música, por lo que no estoy seguro de lo interesante que sería para otras personas. – oggy

Respuesta

2

A partir de reactivo-banana-0.5 y 0.6, la función fromPoll actualiza el comportamiento cada vez que un evento externo desencadena la red de eventos. Se puede acceder a estas actualizaciones como un evento mediante el uso de

eUpdate <- changes bSomeBehavior 

Sin embargo, tenga en cuenta que los comportamientos representan valores variables en el tiempo continuo que no soportan una noción general de un "evento de actualización". La función changes intentará devolver una aproximación útil, pero no hay garantías formales.

Alternativamente, puede cambiar el evento externo para incluir la posición del jugador como parte del addCmdEvent. En su caso, esto significa agregar más datos a los constructores SetStart y SetEnd. A continuación, puede utilizar

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

Ambas soluciones requieren que se observe el valor más reciente como un evento en lugar de un comportamiento. La razón es que los comportamientos creados con stepper siempre devolverán el valor anterior en el momento en que se actualizan ("se quedan atrás en uno"), ya que esto es muy útil para las definiciones recursivas.

En cualquier caso, el problema subyacente es que la posición del jugador se actualiza externamente mucho antes de que ocurra la addCmdEvent, pero el problema es que esto no es lo que ve el caso de la red. Más bien, la red piensa que el comportamiento devuelto por fromPoll se actualiza simultáneamente con el addCmdEvent. De hecho, a menos que tenga acceso a la fuente del evento externo que es responsable de actualizar la posición del jugador, eso es lo único que puede pensar. (Si tiene acceso, puede usar la función fromChanges.)

Me doy cuenta de que este comportamiento de fromPoll es algo insatisfactorio para su caso de uso común. Sin embargo, no estoy seguro si debería arreglarlo en mi biblioteca: hay una compensación entre fromPoll devolviendo el último valor y la función changes tratando de hacer su mejor esfuerzo.Si se devuelve el último valor, entonces el changes se comportará como si hubiera salteado una actualización (cuando el valor se actualizó externamente) y activó una superflua (cuando la red actualiza el valor para que coincida con el externo). Si tiene alguna opinión sobre esto, hágamelo saber.


Nota que la combinación de comportamientos con el operador aplicativo <*> combinará los valores más recientes muy bien.

+0

Gracias por la respuesta. Al final tomé la ruta de sondear los datos de posición externamente e incluirlos en el Evento. Al pensar en ello un poco más, realmente no puedo decidir si hay beneficios conceptuales de obtener el nuevo valor de fromPoll en comparación con obtenerlo de una fuente externa, ni al revés. Por otro lado, no acabo de entender el problema de "bloqueo" de Poll hasta que se lee el valor nuevo, y solo después de disparar el evento que realmente ha desencadenado esta evaluación (al mismo tiempo que el evento de cambios), pero usted conoce su biblioteca mucho mejor que yo – oggy

Cuestiones relacionadas