Short answer: the transform function must take another argument, the value from the API:
transformState v (AppState x) = AppState $ x + v
and you need to use <$> (i.e. apply the function) instead of <$ (i.e. rewrite with constant value):
accumB (AppState 0) $ transformState <$> remoteValueB <@ ebt
Long answer:
Note. I renamed / changed a few things, so please read my explanations accordingly.
What needs to be changed is how you add up your values with accumB . The method of accumB is that it applies a sequence of functions a -> a to the initial value of a to calculate the final value of type a . The way you currently collapse by API values is to always apply the function to increase the application state counter to its original state, completely discarding the input value (using <$ ). Instead, you need to match the input value without replacing it using <$> . What do you need to match the value? Function (according to type accumB )! And this function transformValue eventValue :: AppState -> AppState .
An example based on lists and folds:
*Frp> data State = State Int deriving Show *Frp> let transform x (State c) = State $ x + c *Frp> let xs = [1, 2, 3, 4, 5] -- the API values *Frp> let xsE = transform <$> xs :: [State -> State] -- the event stream *Frp> let accumB = foldr ($) *Frp> accumB (State 0) xsE State 15
(do not forget that a <$> b matches fmap ab or just map ab in the case of lists)
Now consider how you are currently “rewriting” any events from remoteValueB <@ ebt the transformState function function, which means that all rewritten events always contain the same content: the transformState function.
Instead, you should match the input values with some actual functions, for example, one that takes the old state and combines it with the received value and gives a new state value:
remoteValueE :: Event t Int remoteValueE = remoteValueB <@ ebt transformsE :: Event t (AppState -> AppState) transformsE = transformState <$> remoteValueE coreOfTheApp :: Behavior t AppState coreOfTheApp = accumB initialState $ transformsE
I also modified getRemoteApiValue to return a changing value to simulate a real API. Therefore, with some changes in your code, something works here:
import System.Random type RemoteValue = Int -- generate a random value within [0, 10) getRemoteApiValue :: IO RemoteValue getRemoteApiValue = (`mod` 10) <$> randomIO data AppState = AppState { count :: Int } deriving Show transformState :: RemoteValue -> AppState -> AppState transformState v (AppState x) = AppState $ x + v main :: IO () main = start $ do f <- frame [text := "AppState"] myButton <- button f [text := "Go"] output <- staticText f [] set f [layout := minsize (sz 300 200) $ margin 10 $ column 5 [widget myButton, widget output]] let networkDescription :: forall t. Frameworks t => Moment t () networkDescription = do 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] network <- compile networkDescription actuate network