Haskell Language
Plátano reactivo
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!"