Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 反应式系统中行为的动态输入_Haskell_Reactive Banana - Fatal编程技术网

Haskell 反应式系统中行为的动态输入

Haskell 反应式系统中行为的动态输入,haskell,reactive-banana,Haskell,Reactive Banana,当我想在反应式香蕉中处理动态输入时,我通常设想一个大致如下工作的系统: data InputSpecification -- Some data structure that specifies the inputs -- which should be active right now data MyInterestingData -- Some data that is relevant to my business logic

当我想在反应式香蕉中处理动态输入时,我通常设想一个大致如下工作的系统:

data InputSpecification -- Some data structure that specifies the inputs
                        -- which should be active right now

data MyInterestingData -- Some data that is relevant to my business logic
                       -- and is gathered through the dynamic inputs.

emptyData :: MyInterestingData
emptyData = -- Some initial MyInterestingData

setupDynamicInputs :: Event (InputSpecification) -> MomentIO (Behavior MyInterestingData)
setupDynamicInputs specE = do
    newBehavior <- execute $ updateDynamicInputs <$> specE
    switchB emptyData newBehavior

updateDynamicInputs :: InputSpecification -> MomentIO (Behavior MyInterestingData)
updateDynamicInputs = -- Here the dynamic inputs are set up according to
                      -- the specification and set up to update the returned
                      -- Behavior
然后,我可以对从
plainChanges
获取的
事件
使用
setupDynamicInputs
,但是:

但是,不建议采用这种方法[……]

所以我有点不愿意使用这种方法

当规范保持在
行为中时,是否有一种“更干净”的方法使我的输入与规范保持同步

编辑 正如Heinrich Apfelmus在他的回答中指出的,我最初问题的解决方案不是使用
行为
来更新
输入规范
。虽然我能理解其背后的原因,但它并不能解决我所面临的问题,因此我将尝试在这里解释为什么我想使用
行为

只要输入由单个输入指定,通过
事件更新输入就很容易。例如,如果动态输入由一系列输入组成,那么这些输入的规范将只是一个非负整数,表示应该显示多少个输入


一旦通过多个输入获得输入规范,它就会变得更加复杂。例如,假设我们的
InputSpecification
变成
(Word,Word)
,并指定具有给定维度的输入网格。如果我通过两个不同的输入获得这些维度,我将不得不将两个
事件单词
组合成一个
事件(单词,单词)
,这对于
事件
来说并不是一个简单的任务,因为它们没有像
行为
那样的
应用程序
实例。这就是为什么我通常喜欢在这种情况下使用
行为
s的原因,但正如前面所讨论的,当您真正想要创建输入时,它们并不能让您更进一步。因此,如果
行为
在这里不是正确的解决方案,而
事件
往往很难(或者在最坏的情况下不可能)组合在一起,那么这个问题的正确解决方案是什么呢?

嗯,这可能不起作用的一个原因是它可能不起作用。有一个石蕊测试可以确定用
行为
对情况建模是否有意义:如果
行为输入规范
是一个真正连续的函数,会发生什么?比如说,您有一个连续的频率范围(例如,对于无线电台),每个频率都将与必须设置的新输入相关联。如果要进行连续频率扫描,则必须创建并丢弃无限多的输入,这是不可能的。这表明
事件输入规范
是正确类型的背后有更深层次的原因

更一般地说,
行为
类型封装了两个重要的不变量:

  • 它不取决于采样率
  • 您无法检测它何时或多久“变化”。例如,如果您有一个
    事件
    ,其所有出现的事件都具有相同的值
    [(0秒,x),(2秒,x),…]
    ,则此不变量表示对其应用
    步进器
    ,将产生与
    纯x
    无法区分的
    行为
  • 出于实用的原因,可以使用
    更改
    函数绕过不变量2。如果你觉得它“在道德上保持不变”,你可以使用它。例如,只有当行为发生变化时,才可以使用它在屏幕上显示文本值;这比固定采样率下的轮询效率更高。由于上述任何一种行为的视觉最终结果都是相同的,因此在这种情况下,道德上保持不变


    编辑:

    看起来您需要更明确地控制何时更新。在这种情况下,您可以使用显式事件
    e::event()
    ,它跟踪应该何时更新输入。然后,您可以使用以下组合仅在触发此事件时更新输入

    e2 <- plainChanges (imposeChanges b e)
    execute $ updateDynamicInputs <$> e2
    ...
    

    并为此实现
    Applicative
    etc实例。这有点重,但可能正是您需要的。

    谢谢您指出这一点。但这并不能帮助我解决实际问题,所以我编辑了我的答案来澄清这到底是什么。哦,我明白了,我喜欢这个新的例子。然而,它也表明讨论
    行为的语义是重要的。例如,我想象网格的维度是从两个滑块小部件中获取的。如果用户抓住滑块,稍微移动它,但不足以更改其值,会发生什么情况。问:是否会重新创建网格中的所有输入,以便丢失用户之前输入的任何值?我认为您在第一个示例中打算使用
    plainChanges
    ,否则我看不出它是如何进行类型检查的。通常我的目标是重复使用以前创建的输入,以便它们的当前值不会丢失。但是,这仅适用于需要
    事件作为输入的
    accumE
    accumB
    。我认为你在编辑中给出的例子很好地解决了这个问题。组合器
    executerelater::Event(Future(MomentIO A))->Event A
    可以方便地处理
    更改
    ,而无需诉诸
    普通更改
    e2 <- plainChanges (imposeChanges b e)
    execute $ updateDynamicInputs <$> e2
    ...
    
    data Dynamic a = D (Behavior a) (Event a)