I am using Reactive-Banana in a WX interface. I need to retrieve a value from an external service API when a button is pressed.
I have a generic Behavior
based on the data type AppState
that “accums” the transformed changes based on a function transformation (doSomeTransformation
). The values that get transformed are transported by the events and they come from a remote API (getRemoteValue
) when a button on the interface is pressed. I have written a slim version of the code that represents the essential part:
module Main where
{-# LANGUAGE ScopedTypeVariables #-} -- allows "forall t. Moment t"
import Graphics.UI.WX hiding (Event)
import Reactive.Banana
import Reactive.Banana.WX
{-----------------------------------------------------------------------------
Main
------------------------------------------------------------------------------}
data AppState = AppState {
count :: Int
} deriving (Show)
type String = [Char]
main :: IO ()
main = start $ do
f <- frame [text := "AppState"]
myButton <- button f [text := "Go"]
output <- staticText f []
set f [layout := 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
doSomeTransformation :: AppState -> AppState
doSomeTransformation ast = ast { count = count ast }
coreOfTheApp :: Behavior t AppState
coreOfTheApp = accumB initialState $ (doSomeTransformation to combine with myRemoteValue) <$ ebt
sink output [text :== show <$> coreOfTheApp]
network <- compile networkDescription
actuate network
getRemoteApiValue :: IO Int
getRemoteApiValue = return 5
and the cabal conf:
name: brg
version: 0.1.0.0
synopsis: sample frp gui
-- description:
license: PublicDomain
license-file: LICENSE
author: me
maintainer: me@gmail.com
-- copyright:
category: fun
build-type: Simple
-- extra-source-files:
cabal-version: >=1.10
executable bgr
main-is: Main.hs
-- other-modules:
-- other-extensions:
build-depends: base >=4.7 && <4.8
, text
, wx ==0.92.0.0
, wxcore ==0.92.0.0
, transformers-base
, reactive-banana >=0.9 && <0.10
, reactive-banana-wx ==0.9.0.2
hs-source-dirs: src
default-language: Haskell2010
ghc-options: -Wall -O2
My problem here is how to compose doSomeTransformation
and myRemoteValue
in a way that I can use the remote API value as normal event value.
changes
from banana-reactive has the following signature:
changes :: Frameworks t => Behavior t a -> Moment t (Event t (Future a))
which it will wrap my IO Int
from getRemoteApiValue
.
So basically how can I go from:
IO Int -> Moment t (Event t (Future AppState)) -> AppState
?
BTW I am not sure if it is cleaner having this different function signature:
doSomeTransformation :: Int -> AppState -> AppState
, where the Int
value is represented by the API returned value. It sounds like two Behavior
s and one stream. Maybe a bad way to solve the problem?