gpt4 book ai didi

haskell - react 香蕉 : consume parametrized call to an external API

转载 作者:行者123 更新时间:2023-12-04 15:20:32 27 4
gpt4 key购买 nike

从这里的上一个问题开始:
Reactive Banana: how to use values from a remote API and merge them in the event stream

我现在有一点不同的问题:如何使用 Behaviour输出作为 IO 操作的输入并最终显示 IO 操作的结果?

以下是上一个答案中的代码已更改为第二个输出:

import System.Random

type RemoteValue = Int

-- generate a 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 $ do
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 = 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]

sink output2 [text :== show <$> reactimate ( getAnotherRemoteApiValue <@> coreOfTheApp)]

network <- compile networkDescription
actuate network

如您所见,我正在尝试使用应用程序的新状态-> getAnotherRemoteApiValue -> 显示。但它不起作用。

实际上有可能这样做吗?

更新
根据 Erik Allik 和 Heinrich Apfelmus 下面的答案,我有当前的代码情况 - 有效:):
{-# LANGUAGE ScopedTypeVariables #-}

module Main where

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 $ do
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 = do
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 a -> Moment t (Event t b)
mapIO' ioFunc e1 = do
(e2, handler) <- newEvent
reactimate $ (\a -> ioFunc a >>= handler) <$> e1
return e2

remoteValue2E <- mapIO' getAnotherRemoteApiValue appStateE

let remoteValue2B = stepper Nothing $ Just <$> remoteValue2E

sink output1 [text :== show <$> appStateB]
sink output2 [text :== show <$> remoteValue2B]

network <- compile networkDescription
actuate network

getRemoteApiValue :: IO RemoteValue
getRemoteApiValue = do
putStrLn "getRemoteApiValue"
(`mod` 10) <$> randomIO

getAnotherRemoteApiValue :: AppState -> IO RemoteValue
getAnotherRemoteApiValue state = do
putStrLn $ "getAnotherRemoteApiValue: state = " ++ show state
return $ count state

最佳答案

根本问题是一个概念问题:FRP 事件和行为只能以纯粹的方式组合。原则上,不可能有类型的功能,比如说

mapIO' :: (a -> IO b) -> Event a -> Event b

因为相应的 IO Action 的执行顺序是不确定的。

在实践中,有时在组合事件和行为时执行 IO 可能很有用。 execute正如@ErikAllik 所指出的那样,组合器可以做到这一点。取决于 getAnotherRemoteApiValue 的性质,这可能是正确的做法,特别是如果这是函数是幂等的,或者从 RAM 中的位置进行快速查找。

但是,如果计算更复杂,那么使用 reactimate 可能会更好。执行 IO 计算。使用 newEvent创建 AddHandler ,我们可以给出 mapIO' 的实现功能:
mapIO' :: (a -> IO b) -> Event a -> MomentIO (Event b)
mapIO' f e1 = do
(e2, handler) <- newEvent
reactimate $ (\a -> f a >>= handler) <$> e1
return e2

与纯组合器的主要区别
fmap :: (a -> b) -> Event a -> Event b

是后者保证输入和结果事件同时发生,而前者绝对不保证结果事件相对于网络中的其他事件何时发生。

请注意 execute还保证输入和结果同时发生,但对允许的 IO 设置了非正式限制。

有了这个组合 reactimate的技巧与 newEvent可以以类似的方式为 Behaviors 编写类似的组合器。请记住 Reactive.Banana.Frameworks 中的工具箱仅当您处理其精确顺序必然未定义的 IO 操作时才适用。

(为了使这个答案保持最新,我使用了即将发布的响应式香蕉 1.0 中的类型签名。在 0.9 版中, mapIO' 的类型签名是
mapIO' :: Frameworks t => (a -> IO b) -> Event t a -> Moment t (Event t b)

)

关于haskell - react 香蕉 : consume parametrized call to an external API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32916738/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com