Reactive Banana:如何使用远程 API 中的值并将它们合并到事件流中

2024-02-09

我在 WX 界面中使用 Reactive-Banana。 当按下按钮时,我需要从外部服务 API 检索值。

我有一个通用的Behavior基于数据类型AppState基于函数转换“累积”转换后的变化(doSomeTransformation)。转换的值由事件传输,它们来自远程 API (getRemoteValue)当按下界面上的按钮时。我编写了代表基本部分的精简版本的代码:

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

和阴谋集团会议:

name:                brg
version:             0.1.0.0
synopsis:            sample frp gui
-- description:
license:             PublicDomain
license-file:        LICENSE
author:              me
maintainer:          [email protected] /cdn-cgi/l/email-protection
-- 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

我的问题是如何撰写doSomeTransformation and myRemoteValue我可以将远程 API 值用作正常事件值。changes来自banana-reactive 的签名如下:

changes :: Frameworks t => Behavior t a -> Moment t (Event t (Future a))

它将包裹我的IO Int from getRemoteApiValue.

所以基本上我该怎么做:

IO Int -> Moment t (Event t (Future AppState)) -> AppState

?

顺便说一句,我不确定拥有这个不同的函数签名是否更干净:doSomeTransformation :: Int -> AppState -> AppState,其中Intvalue由API返回值表示。听起来像两个Behaviors 和一个流。也许解决问题的方法不好?


简短回答:转换函数需要再接受一个参数,即来自 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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Reactive Banana:如何使用远程 API 中的值并将它们合并到事件流中 的相关文章

  • Haskell - 交替两个列表中的元素

    我正在尝试编写一个 haskell 函数 它接受两个整数列表并生成一个列表 其中包含从两个列表中交替获取的元素 我有这个功能 blend xs ys 一个例子 blend 1 2 3 4 5 6 应该返回 1 4 2 5 3 6 我的逻辑是
  • RxJS 比命令式更快吗? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我对函数式编程和函数式反应式编程比较陌生 我读了很多遍函数式反应式编程的强大力量 好的 可读 避免副作用等 但是 我不知道如何以功能
  • Haskell 中的参数数量和无点 [重复]

    这个问题在这里已经有答案了 对于多重模式匹配 不同数量的参数是不可能的 即使是无点的 foo True b b 2 foo id 例如 不起作用 但 foo True 2 foo id 做 有时我们只能在函数的一部分使用 point fre
  • 测试列表是否已排序

    在 haskell 中找到最小列表确实很容易 foldl1 min 9 5 7 3 7 4 6 10 给我3 我更换了min with lt 测试列表是否已排序 foldl1 lt 9 5 7 3 7 4 6 10 我收到此错误消息 No
  • 结构上强制的自由替代,没有左派分配性

    有一个不错的免费替代品 http hackage haskell org package free 4 12 4 docs Control Alternative Free html在伟大的free包 它将函子提升到左分配替代方案 也就是说
  • Haskell:如何创建将函数应用于元组项的最通用函数

    这是一个个人练习 旨在更好地理解 Haskell 类型系统的局限性 我想创建最通用的函数 将某些函数应用于 2 条目元组中的每个条目 例如 applyToTuple fn a b fn a fn b 我试图让这个函数在以下每种情况下都起作用
  • 我们不应该使用单子绑定来使用循环写下 mfix 的情况

    我一直在尝试写mfix向下使用Control Arrow loop https hackage haskell org package base 4 14 0 0 docs src Control Arrow html loop 我想出了不
  • 不同 hs 文件中的函数分离时堆栈空间溢出

    我有一个巨大的 haskell 文件 它编译和运行没有任何问题 我想将一些函数和类型定义放在通用 hs 文件中的单独模块中 然后将其导入我的主模块中 虽然主程序编译时没有任何错误 它还编译导入的模块 但当我尝试运行它时 出现堆栈空间溢出 I
  • 如何向 Scotty 中间件添加基本身份验证?

    我目前正在制作 Scotty API 但找不到任何 basicAuth 实现的示例 Wai Middleware HttpAuth 具体来说 我想将基本身份验证标头 用户 通行证 添加到我的某些端点 即以 admin 开头的端点 我已经设置
  • 如何在 Haskell 中枚举递归数据类型?

    这篇博文 http lukepalmer wordpress com 2008 05 02 enumerating a context free language 对于如何使用 Omega monad 对角枚举任意语法有一个有趣的解释 他提
  • Haskell 二进制解析

    我一直在尝试在 haskell 中实现一个协议解析器 而且我对这门语言还很陌生 特别是当涉及到 monad 时 我一直在使用binary 0 5 0 2 并描述了协议的标头和所有有效负载 我想要解析的消息如下所示 header payloa
  • Haskell 中的常量变量声明

    要声明常量变量 我可以在 Ruby 中执行以下操作 class COLOR RED 10 BLUE 20 GREEM 30 end COLOR RED回报10 COLOR BLUE回报20 等等 我如何在 Haskell 中实现这一点 我想
  • 如何、为什么以及何时使用“.Internal”模块模式?

    我在上面看到了几个包裹hackage http hackage haskell org packages archive pkg list html其中包含模块名称 Internal作为他们的姓氏组成部分 例如Data ByteString
  • 将 Either 列表转换为其中包含列表的 Either 列表

    我是 Haskell 的初学者 我正在编写一些使用 Haskell 的代码Either https hackage haskell org package base 4 9 0 0 docs Data Either html用于错误处理 E
  • 如何将只缓存某些内容的字段添加到ADT?

    我经常需要向 ADT 添加字段 仅记住一些冗余信息 但我还没有完全弄清楚如何又好又高效地做到这一点 说明问题的最好方法是举个例子 假设我们正在使用无类型 lambda 项 type VSym String data Lambda Var V
  • GHC 是否使用存在类型的动态调度?

    下面的代码是否使用了 C 或 Java 中所理解的动态调度 据我了解 在最后一行 编译器不可能在编译时知道要调用哪个 实现 但代码会编译并产生正确的结果 有人可以解释一下 这背后有什么样的实现 例如 vptr 吗 LANGUAGE Exis
  • 我应该使用镜头中的什么来按索引构建只读吸气剂?

    我有一个内部细节被隐藏的类型 我想提供某种镜头 可以在特定索引处读取所述类型的元素 但是not修改它们 一个Ixed我的类型的实例似乎没有做我想要的事情 因为它明确允许修改 尽管不允许插入或删除 如果我想允许只读索引 我不确定我使用什么 如
  • 在 haskell 中处理 IO 与纯代码

    我正在编写一个shell脚本 我在haskell中的第一个非示例 它应该列出一个目录 获取每个文件大小 进行一些字符串操作 纯代码 然后重命名一些文件 我不确定我做错了什么 所以有两个问题 我应该如何安排这样的程序中的代码 我有一个具体问题
  • Haskell 错误处理方法

    毫无疑问 Haskell 中有多种机制来处理错误并正确处理它们 错误单子 要么 也许 异常等 那么为什么用其他语言编写容易出现异常的代码比用 Haskell 感觉更简单呢 假设我想编写一个命令行工具来处理命令行上传递的文件 我想 验证提供的
  • Haskell 排列库函数 - 请澄清一下?

    这是代码permutationsHaskell 中的函数Data List module permutations a gt a permutations xs0 xs0 perms xs0 where perms perms t ts i

随机推荐

  • 使 google-chrome 浏览器在页面加载时全屏显示

    即使您将其标记为重复 也请考虑在此处回答此问题因为出于某种原因 我无法让它与其他解决方案一起使用 尽管我试图寻求帮助 但没有人回复 我真正想要的是 document ready function browser goes fullscree
  • PHP 中 MySQL 结果的分页

    直到最近我才真正考虑过这个 分页 作为一个问题 当我坐下来专注于它时 我发现自己面临很多问题 我感兴趣的是一个基本的联系人管理系统 用户可以在其中添加 更新 删除 搜索联系人 搜索部分是我需要有效实现分页的地方 我的想法 ve 和 ve 点
  • Google Apps 脚本 - JavaScript 不工作

    我创建了一个简单的网络应用程序 但它不起作用 Code gs function doGet I think this works var output HtmlService createTemplateFromFile index eva
  • 使用 Java 8 的 cobertura-maven-plugin

    是我一个人的问题还是 cobertura maven plugin 不适用于 java 8 当它运行时我得到 INFO cobertura maven plugin 2 6 instrument default provider impl
  • Oozie Shell Action 的 stdout 和 stderr 输出

    在 Oozie 站点中 它说 Shell 操作的 stdout 和 stderr 输出被重定向到运行 shell 命令的 Oozie Launcher 映射减少作业任务 STDOUT 谁能告诉我具体应该去哪里看 Oozie 在 启动器 中运
  • 递归是如何工作的? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 请用最简单的方式解释递归是如何工作的
  • Robotium:测试运行未能完成。预期 N 次测试,已收到 (N-1)

    Android 测试仍然是我头疼的问题 我创建了最简单的应用程序只是为了弄清楚如何Robotium有效 每次测试失败时都会出现错误 Running tests Test running started Test failed to run
  • subprocess.call cd 不起作用[重复]

    这个问题在这里已经有答案了 In 3 pwd Out 3 u Users aarcher Desktop scripts In 5 subprocess call mkdir p os path expanduser file path n
  • 防止在 C++ 中重新绘制窗口

    我正在编写一个全局钩子 DLL 它需要在窗口上使用 GDI 进行一些绘图以响应事件 我的问题是正在绘制的窗口不断重新绘制自身 因此我绘制的内容在我想要的之前就被删除了 有什么办法可以阻止窗户在我需要的时间内绘制任何东西吗 我的钩子目前是WH
  • PHP $_POST 只有 id,没有名称

    有人可以向我解释一下吗 我有以下代码
  • 如何为 CustomClipper 创建的小部件制作合适的边框和阴影

    我有一个Container里面的小部件ClipPath它使用一个CustomClipper 一切正常 我有所需的小部件形状 但是 我找不到为这个自定义形状的小部件制作阴影的方法 另外 我想要一个自动跟随此自定义小部件边缘的轮廓 边框 再次没
  • 不同的 ActionBar.Tab 使用不同的颜色

    我想让 ActionBar 中的所有选项卡都有不同的颜色指示器 例如选项卡 1 为蓝色 选项卡 2 为红色等 为了实现这一点 我为所有颜色创建了不同的选择器 并将它们放在可绘制的不同 xml 中 在 style xml 中我通过以下方式调用
  • 使用正则表达式 OR 运算符解决 2 个条件

    我正在尝试使用 OR 运算符将 2 个正则表达式合并为 1 个 我有一个检查字母后跟 8 位数字是否匹配的方法 Regex IsMatch s A Z d 8 我有另一个只检查 9 位数字的程序 Regex IsMatch s d 9 现在
  • Kubernetes 记录命令 TLS 握手超时

    我正在运行开源 kube 版本 1 9 在运行时出现 TLS 握手超时错误kubectl logs命令 其他kubectl命令工作正常 etc kubernetes pki gt kubectl get pods NAME READY ST
  • 按键或值对 JavaScript 对象进行排序; ES6

    在我问之前 关于这个特定主题有很多讨论 其中大部分与 ES5 相关 并不一定适用于 ES6 我试图得到一些澄清 也许可以帮助下一个在互联网上寻找答案的人 这是专门针对 ES6 的 问题 考虑以下对象结构 const unsorted obj
  • 如何在 Delphi 中使用非托管导出

    我正在用 C 创建一个项目 我想使用不受管理的出口 http sites google com site robertgiesecke Home uploads TOC Samples 后来在Delphi中使用它 那么谁能解释一下 非托管导
  • Google 地图 Android Api v2 的问题

    我一直在尝试实现一个示例应用程序 以研究 Google 地图 API 的工作原理 我对配置本身感到震惊 我似乎无法运行该应用程序 这是我在 Github 上的代码 https github com siva54 SampleMapAppli
  • 使用AJAX和远程PHP上传文件

    我正在尝试使用 AJAx 构建一个上传器 我想使用 AJAX 而不是表单和 Iframe 因为我希望默认 CSS 样式与响应一起使用 问题是 我的 PHP 位于远程服务器上 我正在使用 Shopify 但他们不允许我使用他们的 PHP 服务
  • 是否可以在 Microsoft TreeView Control 6.0 (MSComctlLib.TreeCtrl.2) 中模拟三态复选框?

    我在 Microsoft Access 中使用 Microsoft TreeView Control 6 0 它似乎工作得很好 除了它似乎没有灰色状态 表明检查了一些但不是所有子节点 我已经研究过使用我自己的图像来模拟复选框 但如果我这样做
  • Reactive Banana:如何使用远程 API 中的值并将它们合并到事件流中

    我在 WX 界面中使用 Reactive Banana 当按下按钮时 我需要从外部服务 API 检索值 我有一个通用的Behavior基于数据类型AppState基于函数转换 累积 转换后的变化 doSomeTransformation 转