Haskell Language
Reaktiv banan
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!"