haskell - Reactive Banana: consume parametrized call to an external API -


starting previous question here: reactive banana: how use values remote api , merge them in event stream

i have bit different problem now: how can use behaviour output input io operation , display io operation's result?

below code previous answer changed second output:

import system.random  type remotevalue = int  -- generate random value within [0, 10) getremoteapivalue :: io remotevalue getremoteapivalue = (`mod` 10) <$> randomio  getanotherremoteapivalue :: appstate -> io remotevalue getanotherremoteapivalue state = (`mod` 10) <$> randomio + count state  data appstate = appstate { count :: int } deriving show  transformstate :: remotevalue -> appstate -> appstate transformstate v (appstate x) = appstate $ x + v  main :: io () main = start $     f        <- frame [text := "appstate"]     mybutton <- button f [text := "go"]     output   <- statictext f []     output2  <- statictext f []      set f [layout := minsize (sz 300 200)                    $ margin 10                    $ column 5 [widget mybutton, widget output, widget output2]]      let networkdescription :: forall t. frameworks t => moment t ()         networkdescription =               ebt <- event0 mybutton command            remotevalueb <- frompoll getremoteapivalue           myremotevalue <- changes remotevalueb            let             events = transformstate <$> remotevalueb <@ ebt              coreoftheapp :: behavior t appstate             coreoftheapp = accumb (appstate 0) events            sink output [text :== show <$> coreoftheapp]             sink output2 [text :== show <$> reactimate ( getanotherremoteapivalue <@> coreoftheapp)]       network <- compile networkdescription         actuate network 

as can see trying using new state of application -> getanotherremoteapivalue -> show. doesn't work.

is possible doing that?

update based on erik allik , heinrich apfelmus below answers have current code situation - works :) :

{-# language scopedtypevariables #-}  module main  import system.random import graphics.ui.wx hiding (event, newevent) import reactive.banana import reactive.banana.wx   data appstate = appstate { count :: int } deriving show  initialstate :: appstate initialstate = appstate 0  transformstate :: remotevalue -> appstate -> appstate transformstate v (appstate x) = appstate $ x + v  type remotevalue = int  main :: io () main = start $     f        <- frame [text := "appstate"]     mybutton <- button f [text := "go"]     output1  <- statictext f []     output2  <- statictext f []      set f [layout := minsize (sz 300 200)                    $ margin 10                    $ column 5 [widget mybutton, widget output1, widget output2]]      let networkdescription :: forall t. frameworks t => moment t ()         networkdescription =               ebt <- event0 mybutton command            remotevalue1b <- frompoll getremoteapivalue            let remotevalue1e = remotevalue1b <@ ebt                appstatee = accume initialstate $ transformstate <$> remotevalue1e               appstateb = stepper initialstate appstatee                mapio' :: (a -> io b) -> event t -> moment t (event t b)               mapio' iofunc e1 =                   (e2, handler) <- newevent                   reactimate $ (\a -> iofunc >>= handler) <$> e1                   return e2            remotevalue2e <- mapio' getanotherremoteapivalue appstatee            let remotevalue2b = stepper nothing $ <$> remotevalue2e            sink output1 [text :== show <$> appstateb]            sink output2 [text :== show <$> remotevalue2b]       network <- compile networkdescription         actuate network  getremoteapivalue :: io remotevalue getremoteapivalue =   putstrln "getremoteapivalue"   (`mod` 10) <$> randomio  getanotherremoteapivalue :: appstate -> io remotevalue getanotherremoteapivalue state =   putstrln $ "getanotherremoteapivalue: state = " ++ show state   return $ count state 

the fundamental problem conceptual one: frp events , behaviors can combined in pure way. in principle, not possible have function of type, say

mapio' :: (a -> io b) -> event -> event b 

because order in corresponding io actions executed undefined.


in practice, may useful perform io while combining events , behaviors. execute combinator can this, @erikallik indicates. depending on nature of getanotherremoteapivalue, may right thing do, in particular if function idempotent, or quick lookup location in ram.

however, if computation more involved, better use reactimate perform io computation. using newevent create addhandler, can give implementation of mapio' function:

mapio' :: (a -> io b) -> event -> momentio (event b) mapio' f e1 =     (e2, handler) <- newevent     reactimate $ (\a -> f >>= handler) <$> e1     return e2 

the key difference pure combinator

fmap :: (a -> b) -> event -> event b 

is latter guarantees input , result events occur simultaneously, while former gives absolutely no guarantee when result event occurs in relation other events in network.

note execute guarantees input , result have simultaneous occurrences, places informal restrictions on io allowed.


with trick of combining reactimate newevent similar combinator can written behaviors in similar fashion. keep in mind toolbox reactive.banana.frameworks appropriate if dealing io actions precise order undefined.


(to keep answer current, have used type signatures upcoming reactive-banana 1.0. in version 0.9, type signature mapio' is

mapio' :: frameworks t => (a -> io b) -> event t -> moment t (event t b) 

)


Comments

Popular posts from this blog

resizing Telegram inline keyboard -

command line - How can a Python program background itself? -

php - "cURL error 28: Resolving timed out" on Wordpress on Azure App Service on Linux -