Zoeken…


Externe gebeurtenissen in de bibliotheek injecteren

Dit voorbeeld is niet gekoppeld aan een concrete GUI-toolkit, zoals reactieve-banana-wx bijvoorbeeld. In plaats daarvan wordt getoond hoe willekeurige IO acties in FRP-machines kunnen worden geïnjecteerd.

De Control.Event.Handler module geeft een addHandler functie die een paar creëert AddHandler a en a -> IO () waarden. De eerste wordt gebruikt door reactieve-banaan zelf om een Event a waarde te verkrijgen, terwijl de laatste een eenvoudige functie is die wordt gebruikt om de overeenkomstige gebeurtenis te activeren.

import Data.Char (toUpper)

import Control.Event.Handler
import Reactive.Banana

main = do
    (inputHandler, inputFire) <- newAddHandler

In ons geval het a parameter van de handler van het type String , maar de code waarmee compiler afleiden dat later zal worden geschreven.

Nu definiëren we het EventNetwork dat ons FRP-aangedreven systeem beschrijft. Dit wordt gedaan met behulp van de compile :

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

De functie fromAddHandler transformeert AddHandler a waarde in een Event a , die in het volgende voorbeeld wordt behandeld.

Ten slotte lanceren we onze "event loop", die gebeurtenissen op gebruikersinvoer zou activeren:

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

Soort evenement

In reactieve banaan vertegenwoordigt het type Event een stroom van sommige gebeurtenissen in de tijd. Een Event is vergelijkbaar met een analoog impulssignaal in die zin dat het niet continu in de tijd is. Hierdoor is Event alleen een instantie van de Functor typeclass. Je kunt twee Event niet samenvoegen omdat ze op verschillende tijdstippen kunnen vuren. Je kunt iets doen met de [huidige] waarde van een Event en daarop reageren met een IO actie.

Transformaties op Event 's waarde worden gedaan met behulp van 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

Reageren op een Event gebeurt op dezelfde manier. Eerst fmap het met een actie van type a -> IO () en geef je het vervolgens door aan de reactimate functie:

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

Wanneer inputFire "something" wordt genoemd, wordt "SOMETHING" afgedrukt.

Gedragstype

Om continue signalen weer te geven, heeft reactief-banaan een Behavior a . In tegenstelling tot Event is een Behavior een Applicative , waarmee u n Behavior kunt combineren met behulp van een pure functie (met <$> en <*> ).

Om een Behavior a te verkrijgen van de Event a er een accumE functie:

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

accumE neemt de initiële waarde van Behavior en een Event , met een functie die deze op de nieuwe waarde zou zetten.

Net als bij Event s, kunt u fmap om te werken met de huidige waarde van Behavior , maar u kunt ze ook combineren met (<*>) .

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'

Om te reageren op Behavior is er een 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

Het enige dat moet worden opgemerkt, is dat changes Event (Future a) plaats van Event a retourneren. Daarom moet reactimate' worden gebruikt in plaats van reactimate . De reden hiervoor is te vinden in de documentatie.

Activeren van EventNetworks

EventNetwork 's geretourneerd door compile moeten worden geactiveerd voordat gereactiveerde gebeurtenissen effect hebben.

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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow