Recherche…


Injection d'événements externes dans la bibliothèque

Cet exemple n'est lié à aucune boîte à outils graphique, comme le fait réactif-banana-wx, par exemple. Au lieu de cela, il montre comment injecter des actions IO arbitraires dans les machines FRP.

Le module Control.Event.Handler fournit une fonction addHandler qui crée une paire de valeurs AddHandler a et a -> IO () . Le premier est utilisé par reactive-banana lui-même pour obtenir un Event a , alors que le second est une fonction simple utilisée pour déclencher l'événement correspondant.

import Data.Char (toUpper)

import Control.Event.Handler
import Reactive.Banana

main = do
    (inputHandler, inputFire) <- newAddHandler

Dans notre cas a paramètre du gestionnaire est de type String , mais le code qui permet de déduire du compilateur qui sera écrit plus tard.

Nous définissons maintenant le EventNetwork qui décrit notre système FRP. Ceci est fait en utilisant la fonction de compile :

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

La fonction fromAddHandler transforme AddHandler a valeur Event a , qui est traitée dans l'exemple suivant.

Enfin, nous lançons notre "boucle d'événements", qui déclencherait des événements sur la saisie de l'utilisateur:

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

Type d'événement

En mode réactif-banane, le type d' Event représente un flux de certains événements dans le temps. Un Event est similaire à un signal d'impulsion analogique dans le sens où il n'est pas continu dans le temps. Par conséquent, Event est une instance de la Functor types Functor uniquement. Vous ne pouvez pas combiner deux Event ensemble car ils peuvent tirer à des moments différents. Vous pouvez faire quelque chose avec la valeur [actuelle] d'un Event et y réagir avec une action IO .

Les transformations sur la valeur de l' Event sont effectuées en utilisant 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

Réagir à un Event se fait de la même manière. D'abord, vous le fmap avec une action de type a -> IO () et vous la transmettez ensuite à la fonction reactimate :

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

Maintenant, chaque fois que inputFire "something" est appelé "SOMETHING" , "SOMETHING" sera imprimé.

Type de comportement

Pour représenter des signaux continus, les caractéristiques réactives-bananes Behavior a type. Contrairement à Event , un Behavior est un Applicative , qui vous permet de combiner n Behavior aide d'une fonction pure n-aire (en utilisant <$> et <*> ).

Pour obtenir un Behavior a partir de l' Event a il existe accumE fonction d' accumE :

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

accumE prend la valeur initiale de Behavior et un Event , contenant une fonction qui lui donnerait la nouvelle valeur.

Comme avec Event s, vous pouvez utiliser fmap pour travailler avec la valeur actuelle du Behavior , mais vous pouvez également les combiner avec (<*>) .

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'

Pour réagir aux changements de Behavior , il y a une fonction 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

La seule chose à noter est que les changes renvoient l' Event (Future a) au lieu de l' Event a . À cause de cela, reactimate' doit être utilisé au lieu de reactimate . La justification derrière cela peut être obtenue de la documentation.

Activer les réseaux d'événements

EventNetwork retournés par compile doivent être activés avant que les événements réactivés aient un effet.

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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow