Implementando zipE :: Evento ta -> Evento tb -> Evento t (a,b)

Soy nuevo en el banano reactivo y el FRP en general, así que pido disculpas si me estoy perdiendo algo obvio.

Para mi proyecto (a GDB / MI front-end) Estoy usando banana reactiva (versión 0.6.0.0) tanto para la GUI como para los módulos lógicos de front-end. El primero funciona muy bien, pero para el segundo aparentemente necesito combinadores adicionales.

Uno de ellos es zipE :: Event t a -> Event t b -> Event t (a, b). Desafortunadamente, todo lo que pude encontrar es una solución en la mónada NetworkDescription que usa changes y no es genérico en los tipos de eventos:

zipE :: Event t Int -> Event t String -> NetworkDescription t (Event t (Int, String))
zipE ea eb = changes $ (,) <$> stepper 0 ea <*> stepper "" eb

Por supuesto, no estoy satisfecho con esto. Por lo tanto, quería preguntar cómo implementar una función zipE genérica sin usar changes (que se desaconseja usar para fines que no sean GUI).

Otros intentos fallaron, por ejemplo

zipE :: Num a => Event t a -> Event t b -> Event t (a,b)
zipE ea eb = apply (stepper (0,) ((,) <$> ea)) eb

da como resultado que los primeros elementos de las tuplas se desplacen en uno, supongo que debido al "leve retraso" introducido por stepper. Pero no veo cómo obtener un comportamiento de un evento sin stepper (o accumB para el caso) y no veo cómo aplicar una función a un evento sin un comportamiento. Y, en general, no veo cómo proporcionar un valor inicial a paso a paso en el caso de un tipo genérico.

preguntado el 31 de julio de 12 a las 15:07

ea y eb no van a disparar al mismo tiempo. (Si sabe que se van a disparar al mismo tiempo porque ambos se derivan del mismo evento subyacente, probablemente sea mejor volver a procesar ese evento subyacente). ¿Qué quiere que suceda cuando uno se dispara y el otro no? t? -

Dave, tienes razón. Necesito un diseño diferente para mi red de eventos :-/ Gracias por señalar esto. -

De hecho, necesitaba una red de eventos diferente. Inicialmente, quería comprimir los dos eventos para alimentar las tuplas en f :: (a,b) -> IO (). Lo que tengo ahora en cambio es f :: a -> b -> IO () y reactimate $ (f <$> stepper 0 aE) <@> bE. -

1 Respuestas

Tiene dificultad para definir zipE porque no tiene sentido semántico. Si consideras las definiciones semánticas

Event a == [(Time, a)]
Event b == [(Time, b)]

no hay una forma natural de comprimirlos, porque en general cada evento será en un momento diferente.

Es posible comprimirlos usando una suma en lugar de un producto.

zipE :: Event a -> Event b -> Event (Either a b)
zipE aE bE = (Left <$> aE) `mappend` (Right <$> bE)

Si realmente necesitas tener ambos a y b al mismo tiempo, la solución apropiada es crear un Behavior que se acumula sobre uno u otro, o el combinado Either corriente como arriba.

editar: un ejemplo de una forma de acumular sobre el flujo fusionado (no probado). También son posibles otras implementaciones. Esto no hace que ambos eventos ocurran al mismo tiempo, sino que le permite combinar el estado actual con estados pasados ​​para que siempre pueda tener disponible el más reciente de ambos. Left y Right valores.

currentAandB :: a -> b -> Event a -> Event b -> Event (a,b)
currentAandB a0 b0 aE bE = accumE (a0,b0) (mergefn <$> zipE aE bE)
    where
        mergefn (Left a)  (_,b) = (a,b)
        mergefn (Right b) (a,_) = (a,b)

Todavía es necesario proporcionar valores iniciales para ambos Event arroyos Piénsalo de esta manera: si solo has tenido eventos de Event a, ¿qué valor debe tener la segunda parte de la tupla?

Respondido 31 Jul 12, 17:07

Juan, gracias por ayudarme. Me gustaría saber más sobre la respuesta apropiada que está mencionando. ¿Podría explicar cómo la acumulación sobre uno u otro hace que ambos eventos ocurran al mismo tiempo? Lo siento, si eso es obvio. Simplemente no lo veo. - coptón

@copton: He publicado un ejemplo de una forma de hacer esto. En cuanto a los valores iniciales, si piensa en el estado inicial de su problema, probablemente encontrará una respuesta sensata. O puede usar una combinación de Maybe, Data.Traversable.sequenceA y filterJust para producir solo una salida después de haber recibido tanto un a y b. - John L

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.