Sök…


Injicera externa händelser i biblioteket

Detta exempel är inte bundet till några konkreta GUI-verktygssatser, som reaktiva-banan-wx till exempel gör. Istället visar det hur man injicerar arbiträra IO åtgärder i FRP-maskiner.

Control.Event.Handler modulen tillhandahåller en addHandler funktion som skapar ett par AddHandler a och a -> IO () -värden. Den förstnämnda används av reaktiv-banan själv för att erhålla en Event a värde, medan den senare är en vanlig funktion som används för att trigga motsvarande händelse.

import Data.Char (toUpper)

import Control.Event.Handler
import Reactive.Banana

main = do
    (inputHandler, inputFire) <- newAddHandler

I vårt fall a parameter föraren är av typen String , men koden som låter kompilatorn dra slutsatsen att kommer att skrivas senare.

Nu definierar vi EventNetwork som beskriver vårt FRP-driven system. Detta görs med compile :

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

Funktionen fromAddHandler omvandlar AddHandler a värde till AddHandler a till en Event a , som behandlas i nästa exempel.

Slutligen lanserar vi vår "event loop", som skulle avfyra händelser på användarens input:

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

Event typ

I reaktiv-banan representerar Event en ström av vissa händelser i tid. En Event liknar en analog impulssignal i den meningen att den inte är kontinuerlig i tid. Som ett resultat är Event en instans av Functor typkategori. Du kan inte kombinera två Event tillsammans eftersom de kan avfyra vid olika tidpunkter. Du kan göra något med en Event [nuvarande] värde och reagera på det med någon IO åtgärd.

Transformationer på Event värde görs med 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

Reaktion på en Event görs på samma sätt. Först fmap det med en åtgärd av typ a -> IO () och sedan skicka den till reactimate funktion:

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

När inputFire "something" kallas skulle "SOMETHING" skrivas ut.

Beteende typ

För att representera kontinuerliga signaler, reaktiva-banan funktioner Funktioner Behavior a typ. Till skillnad från Event är ett Behavior ett Applicative , som låter dig kombinera n Behavior med en n-ary ren funktion (med <$> och <*> ).

För att erhålla ett Behavior a från Event a finns en accumE :

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

accumE tar Behavior initialvärde och en Event innehåller en funktion som skulle ställa in det på det nya värdet.

Som med Event kan du använda fmap att arbeta med aktuellt Behavior , men du kan också kombinera dem med (<*>) .

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'

För att reagera på Behavior finns en 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

Det enda som bör noteras är att changes returnerar Event (Future a) istället för Event a . På grund av detta reactimate' användas istället för reactimate . Motiveringen bakom detta kan erhållas från dokumentationen.

Aktivera EventNetworks

EventNetwork returneras med compile måste aktiveras innan reaktiverade händelser har effekt.

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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow