Buscar..


Inyectando eventos externos en la biblioteca.

Este ejemplo no está vinculado a ningún conjunto de herramientas GUI concreto, como hace el caso de reactivo-banana-wx, por ejemplo. En su lugar, muestra cómo inyectar acciones arbitrarias de IO / IO en la maquinaria de FRP.

El módulo Control.Event.Handler proporciona una función addHandler que crea un par de AddHandler a y a -> IO () . El primero es utilizado por el propio banana reactiva para obtener un Event a valor, mientras que el segundo es una función simple que se usa para desencadenar el evento correspondiente.

import Data.Char (toUpper)

import Control.Event.Handler
import Reactive.Banana

main = do
    (inputHandler, inputFire) <- newAddHandler

En nuestro caso el a parámetro del controlador es de tipo String , pero el código que permite inferir que el compilador se escribirá más tarde.

Ahora definimos la EventNetwork que describe nuestro sistema controlado por FRP. Esto se hace usando la función de compile :

main = do
    (inputHandler, inputFire) <- newAddHandler
    compile $ do
        inputEvent <- fromAddHandler inputHandler

La función fromAddHandler transforma AddHandler a valor AddHandler a en un Event a , que se trata en el siguiente ejemplo.

Finalmente, lanzamos nuestro "bucle de eventos", que dispararía eventos en la entrada del usuario:

main = do
    (inputHandler, inputFire) <- newAddHandler
    compile $ do
        ...
    forever $ do
        input <- getLine
        inputFire input

Tipo de evento

En reactive-banana, el tipo de Event representa una secuencia de algunos eventos en el tiempo. Un Event es similar a una señal de impulso analógica en el sentido de que no es continua en el tiempo. Como resultado, Event es una instancia de la clase de tipos de Functor solamente. No puedes combinar dos Event s juntos porque pueden disparar en diferentes momentos. Puede hacer algo con el valor [actual] de un Event y reaccionar a él con alguna acción IO .

Las transformaciones en el valor del Event se realizan usando fmap :

main = do
    (inputHandler, inputFire) <- newAddHandler
    compile $ do
        inputEvent <- fromAddHandler inputHandler
        -- turn all characters in the signal to upper case
        let inputEvent' = fmap (map toUpper) inputEvent

Reaccionar ante un Event se hace de la misma manera. Primero fmap con una acción de tipo a -> IO () y luego reactimate para reactimate función:

main = do
    (inputHandler, inputFire) <- newAddHandler
    compile $ do
        inputEvent <- fromAddHandler inputHandler
        -- turn all characters in the signal to upper case
        let inputEvent' = fmap (map toUpper) inputEvent
        let inputEventReaction = fmap putStrLn inputEvent' -- this has type `Event (IO ())
        reactimate inputEventReaction

Ahora, cada vez que se inputFire "something" , se imprimirá "SOMETHING" .

Tipo de comportamiento

Para representar señales continuas, características reactivas de banana Behavior a tipo. A diferencia del Event , un Behavior es un Applicative , que le permite combinar n Behavior usando una función pura n-aría (usando <$> y <*> ).

Para obtener un Behavior a del Event a hay Event a función de accumE :

main = do
    (inputHandler, inputFire) <- newAddHandler
    compile $ do
        ...
        inputBehavior <- accumE "" $ fmap (\oldValue newValue -> newValue) inputEvent

accumE toma el valor inicial de Behavior y un Event , que contiene una función que lo establecería en el nuevo valor.

Al igual que con los Event s, puede usar fmap para trabajar con el valor del Behavior actual, pero también puede combinarlos con (<*>) .

main = do
    (inputHandler, inputFire) <- newAddHandler
    compile $ do
        ...
        inputBehavior  <- accumE "" $ fmap (\oldValue newValue -> newValue) inputEvent
        inputBehavior' <- accumE "" $ fmap (\oldValue newValue -> newValue) inputEvent
        let constantTrueBehavior = (==) <$> inputBehavior <*> inputBehavior'

Para reaccionar ante los cambios de Behavior hay una función de changes :

main = do
    (inputHandler, inputFire) <- newAddHandler
    compile $ do
        ...
        inputBehavior  <- accumE "" $ fmap (\oldValue newValue -> newValue) inputEvent
        inputBehavior' <- accumE "" $ fmap (\oldValue newValue -> newValue) inputEvent
        let constantTrueBehavior = (==) <$> inputBehavior <*> inputBehavior'
        inputChanged <- changes inputBehavior

Lo único que se debe tener en cuenta es que los changes devuelven el Event (Future a) lugar del Event a . Debido a esto, reactimate' se debe utilizar en lugar de reactimate . La razón detrás de esto se puede obtener de la documentación.

Actuating EventNetworks

EventNetwork devueltos por compile deben activarse antes de que los eventos reactivados tengan un efecto.

main = do
    (inputHandler, inputFire) <- newAddHandler

    eventNetwork <- compile $ do
        inputEvent <- fromAddHandler inputHandler
        let inputEventReaction = fmap putStrLn inputEvent
        reactimate inputEventReaction

    inputFire "This will NOT be printed to the console!"
    actuate eventNetwork
    inputFire "This WILL be printed to the console!"


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow