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!"