简短回答:转换函数需要再接受一个参数,即来自 API 的值:
transformState v (AppState x) = AppState $ x + v
你需要使用<$>
(即应用功能)而不是<$
(即用常量值覆盖):
accumB (AppState 0) $ transformState <$> remoteValueB <@ ebt
长答案:
注意:我已经重命名/更改了一些内容,因此请相应地阅读我的解释
需要改变的是使用以下方式折叠传入值的方式accumB
。道路accumB
工作原理是它应用了一系列函数a -> a
到种子值a
,计算类型的最终值a
。当前折叠 API 值的方式是始终将应用程序状态计数增量函数应用于初始状态,完全丢弃传入值(通过使用<$
)。相反,你需要map传入的值不是replace它,使用<$>
。您需要将值映射到什么?一个函数(根据类型accumB
)!这个函数是transformValue eventValue :: AppState -> AppState
.
基于列表和折叠的示例:
*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
(别忘了a <$> b
是相同的fmap a b
, 要不就map a b
对于列表的情况)
现在考虑一下您当前如何“覆盖”来自remoteValueB <@ ebt
与(函数)常数transformState
,这意味着所有到达的被覆盖事件始终保留相同的内容:transformState
功能。
相反,您想要的是将传入值映射到一些实际函数,例如采用旧状态并将其与到达值组合并产生新状态值的函数:
remoteValueE :: Event t Int
remoteValueE = remoteValueB <@ ebt
transformsE :: Event t (AppState -> AppState)
transformsE = transformState <$> remoteValueE
coreOfTheApp :: Behavior t AppState
coreOfTheApp = accumB initialState $ transformsE
我也变了getRemoteApiValue
返回变化的值来模仿真实的 API。因此,通过对代码进行一些修改,可以得到以下效果:
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