Suche…


Einfügen externer Ereignisse in die Bibliothek

Dieses Beispiel ist nicht an ein konkretes GUI-Toolkit gebunden, wie es zum Beispiel die reaktive Banane-wx ist. Stattdessen zeigt es , wie willkürliche einzuspritzen IO Aktionen in FRP Maschinen.

Das Control.Event.Handler Modul stellt eine addHandler Funktion addHandler , die ein Paar von AddHandler a und a -> IO () . Ersteres wird von der reaktiven Banane selbst verwendet, um einen Event a Wert zu erhalten, während letzteres eine einfache Funktion ist, die zum Auslösen des entsprechenden Events verwendet wird.

import Data.Char (toUpper)

import Control.Event.Handler
import Reactive.Banana

main = do
    (inputHandler, inputFire) <- newAddHandler

In unserem Fall ist die a Parameter des Handlers ist vom Typ String , aber der Code, den Compiler schließen läßt , die später geschrieben werden.

Nun definieren wir das EventNetwork , das unser FRP-gesteuertes System beschreibt. Dies geschieht mit der compile Funktion:

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

Die Funktion fromAddHandler wandelt AddHandler a in ein Event a , das im nächsten Beispiel behandelt wird.

Schließlich starten wir unsere "Ereignisschleife", die auf Benutzereingaben Ereignisse auslöst:

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

Ereignistyp

In reaktiver Banane der Event stellt Art einen Strom von einigen Ereignissen in der Zeit. Ein Event ähnelt einem analogen Impulssignal in dem Sinne, dass es zeitlich nicht stetig ist. Daher ist Event nur eine Instanz der Functor . Sie können nicht zwei Event miteinander kombinieren, da sie zu unterschiedlichen Zeiten ausgelöst werden. Sie können etwas mit dem [aktuellen] Wert eines Event und darauf mit einer IO Aktion reagieren.

Transformationen für den Wert von Event werden mit 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

Auf ein Event reagieren erfolgt auf dieselbe Weise. Zuerst fmap Sie es mit einer Aktion vom Typ a -> IO () und übergeben es dann an die 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

Immer wenn inputFire "something" genannt wird, wird "SOMETHING" gedruckt.

Verhaltenstyp

Um kontinuierliche Signale darzustellen, verhalten sich reaktive Bananenmerkmale Behavior a Typ. Im Gegensatz zu Event ist ein Behavior ein Applicative , mit dem Sie n Behavior mit einer n-ary pure-Funktion (mit <$> und <*> ) kombinieren können.

Um ein Behavior a vom Event a gibt es accumE Funktion accumE :

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

accumE übernimmt den Anfangswert von Behavior und ein Event , das eine Funktion enthält, die den neuen Wert festlegen würde.

Wie bei Event können Sie fmap , um mit dem aktuellen Behavior zu arbeiten. Sie können sie jedoch auch mit (<*>) kombinieren.

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'

Um auf Behavior zu reagieren, gibt es eine 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

Das einzige, was beachtet werden sollte, ist, dass changes Event (Future a) statt Event a . Aus diesem reactimate' sollte reactimate anstelle von reactimate . Die Gründe dafür können der Dokumentation entnommen werden.

EventNetworks aktivieren

EventNetwork von compile zurückgegeben werden compile müssen aktiviert werden, bevor reaktivierte Ereignisse wirken.

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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow