“现在行为”在玻璃钢 [英] "Behavior now" in FRP

查看:121
本文介绍了“现在行为”在玻璃钢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在之前的SO问题中(是否有可能?:行为t [行为ta] - >行为t [a] )我们正在分析行为 <$的存在c $ c>加入(使用反应 - 香蕉条款)。

 行为t(行为ta) - >行为ta 

在语义模型中实现如下

  type行为ta = t  - > a 

behaviorNow :: Behavior t(Behavior t a) - >行为ta
behaviorNow ft = ftt

直接执行这个操作是不幸的,因为我们可以生产a 行为 Monad 使用 const behaviorNow behaviorNow 违反了FRP的语义吗?



I如果有意义的话,我很乐意听到任何其他FRP系统的术语以及比较结果。

在基于轮询的FRP中系统中,任何行为都有意义加入




  • join bb 是通过抽样 bb b 的示例>


在基于推送的FRP中,任何与其他步骤函数组成的步进函数的行为都有一个有意义的>> = 加入。通过>> = 推送值可以用命令来描述:


  • 当绑定的参数发生变化时,评估绑定并将

    • 更改当前步骤函数返回的步骤函数


      • 将值更改为当前步骤函数的值
      / li>
    • 当当前步骤函数的值发生变化时,更改值


      提供一个 Monad 实例可能稍微不受欢迎,因为它可能由库用户优先选择,即使效率较低。例如,这个无关的答案当使用>> = 构建计算时,执行更多的工作,而不是使用<> $ b Conal Elliott以声明性术语描述了一个连接,用于同时推送和轮询构建行为的值来自步骤函数:

         -  Reactive是一个只能是一个步骤函数的行为
      data Reactive a = a `Stepper`事件a
      newtype事件a = Ev(Future(Reactive a))

      join :: Reactive(Reactive a) - > Reactive a
      join((a`Stepper` Ev ur)`Stepper` Ev urr)=
      ((``switcher` Ev urr)< $> ur)_ + _(join< $ > urr)

      switcher :: Reactive a - >事件(Reactive a) - > Reactive a
      r`switcher` er = join(r`Stepper` er)

      其中 Future 是我们尚未见过的值的类型, _ + _ 是两个 Future 发生的可能性,< $> 是中缀 fmap 未来 s。 [1]



      如果我们没有提供任何其他的创建行为的方法,而不是


      • 常量函数一个步骤函数)
      • 一个步进器,它记住了事件的最近值

      • 应用了组合器本身没有的各种行为组合器't time-varying



      然后每个行为都是一个step函数,我们可以使用这个或者类似的 Monad



      只有当我们想要具有连续的行为或者是某个事件以外的行为时才会遇到困难发生。考虑我们是否有以下几种:

        time :: Behavior tt 

      这是跟踪当前时间的行为。用于轮询系统的 Monad 实例仍然是相同的,但我们不能再可靠地通过系统推送更改。当我们做一些简单的事情时会发生什么 time>> = \ x - >如果是x,则返回0否则返回1 (其中 am t 在早上的时间是正确的)?我们对>> = 以上的定义和Elliot的 join 都不能承认知道何时改变的最优化;它不断变化。我们对>> = 所能做的最好的事情就像这样: 如果我们知道绑定的参数是步骤值,那么当绑定的参数发生变化时,评估绑定和

    • 节点,然后

    • $ b $ li $ ul

    • 将当前步进函数更改为返回的步进函数 / li>



    • b
    • 将值更改为当前步骤函数的值



      • 如果当前步骤函数的值更改,请更改值


    • 否则


      • 为此>> = 返回一个抽象语法树



      对于加入表单,我们会减少做一些类似的事情,只需在实例中记录AST,即 join 中的外部行为不是一个step函数。

      另外,无论是否引发任何其他事件,使用此输入构建的任何内容都可能在中午和午夜发生变化。从实施的角度来看,我们最好的选择似乎是连续轮询<$> c $ c> time ,并用由轮询事件构建的步进器替换它所使用的任何地方。这不会更新事件之间的值,所以现在我们的库的用户不能可靠地轮询值。



      实现的最佳选择是保持抽象语法树就像这些任意行为发生的事情,并没有提供从行为中产生事件的方法。然后,行为可以被轮询,但是不会有任何更新被推送给他们。在这种情况下,我们不妨将它放在库之外,让用户绕过AST(它们可以获得 Free ),并让用户评估每次轮询时都是整个AST。我们不能再为图书馆用户优化它,因为任何这样的值都可以不断变化。



      最后一个选项是,但它涉及很多的复杂性。引入连续变化值的性质和连续变化值的计算的可预测性概念。这将允许我们为更大的时变行为子集提供Monad接口,但不是为所有这些子接口提供Monad接口。在程序的其他部分,这种复杂性已经是需要的,但我不知道任何试图解决这个问题的符号数学以外的库。

      In a previous SO question (Is it possible?: Behavior t [Behavior t a] -> Behavior t [a]) we were analyzing the existence of a Behavior join (to use reactive-banana terms).

      Behavior t (Behavior t a) -> Behavior t a
      

      Implemented in the semantic model as follows

      type Behavior t a = t -> a
      
      behaviorNow :: Behavior t (Behavior t a) -> Behavior t a
      behaviorNow f t = f t t
      

      While implementing this directly would be unfortunate since we could produce a Behavior Monad using const and behaviorNow, if and how does behaviorNow violate the semantics of FRP?

      I'd love to hear answers using the terminology of any other FRP system along with comparisons if meaningful.

      解决方案

      In a poll based FRP system, any behavior has a meaningful join

      • the sample of join bb is the sample of the b obtained by sampling bb

      In push based FRP, any behavior that is a step function composed with other step functions has a meaningful >>= and join. Pushing values through >>= can be described in imperative terms:

      • when the argument of the bind changes, evaluate the bind and
        • change the current step function to the returned step function
        • change the value to the value of the current step function
      • when the value of the current step function changes, change the value

      Providing a Monad instance may be slightly undesirable because it is likely to be chosen by preference by library users, even if it is less efficient. For example, the code in this unrelated answer performs more work when a computation was built with >>= than if it had been equivalently built with <*>.

      Conal Elliott described in declarative terms a join for simultaneously pushing and polling values for behaviors built from step functions:

      -- Reactive is a behavior that can only be a step function
      data Reactive a = a `Stepper` Event a
      newtype Event a = Ev (Future (Reactive a))
      
      join :: Reactive (Reactive a) -> Reactive a
      join ((a `Stepper` Ev ur) `Stepper` Ev urr ) =
          ((`switcher` Ev urr ) <$> ur) _+_ (join <$> urr )
      
      switcher :: Reactive a -> Event (Reactive a) -> Reactive a
      r `switcher` er = join (r `Stepper` er)
      

      where Future is the type for a value we haven't seen yet, _+_ is the first of the two Future possibilities to occur, and <$> is infix fmap on Futures. [1]

      If we don't provide any other means of creating behaviors than

      • the constant function (which is trivially a step function)
      • a "stepper" that remembers the most recent value of an event
      • application of various combinators of behaviors where the combinators themselves aren't time-varying

      then every behavior is a step function and we can use this or a similar Monad instance for behaviors.

      Difficulties only arise when we want to have behaviors that are continuous or are a function of some time other than when an event occurred. Consider if we had the following

      time :: Behavior t t
      

      which is the behavior that tracks the current time. A Monad instance for polling the system would still be the same, but we can no longer push changes through the system reliably. What happens when we make something as simple as time >>= \x -> if am x then return 0 else return 1 (where am t is true for times in the morning)? Neither our definition of >>= above nor Elliot's join can admit the optimization of knowing when the time changes; it changes continuously. The best we could do to >>= is something like:

      • if we know that the argument to the bind is step valued then
        • when the argument of the bind changes, evaluate the bind and
          • change the current step function to the returned step function
          • change the value to the value of the current step function
        • when the value of the current step function changes, change the value
      • otherwise
        • return an abstract syntax tree for this >>=

      For the join form, we would be reduced to doing something similar, and simply record the AST in the instance that the outer behavior in a join isn't a step function.

      Additionally, anything built using this as an input could change at noon and midnight, whether or not any other event was raised. It would taint everything from that point on with the inability to reliably push events.

      From an implementation point of view, our best option would seem to be to continuously poll time, and replace anywhere it was used with a stepper built from the polling events. This wouldn't update values between events, so now users of our library can't reliably poll values.

      Our best choice for an implementation would be to keep an abstract syntax tree of what happened with arbitrary behaviors like these and provide no means to generate events from behaviors. Then behaviors can be polled, but no updates will ever be pushed for them. In that case, we might as well leave it out of the library, and let the user pass around ASTs (which they can get for Free), and let the user evaluate the entire AST every time it's polled. We can't optimize it any more for the library user, since any value like this can change continuously.

      There is one final option, but it involves introducing quite a bit of complexity. Introduce the notion of predictability for properties of continuously varying values and computations of continuously varying values. This would allow us to provide a Monad interface for a larger subset of time-varying behaviors, but not for all of them. This complexity is already desirable in other parts of programs, but I don't know of any libraries outside symbolic math which attempt to address this.

      这篇关于“现在行为”在玻璃钢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆