处理反应香蕉中的当前时间 [英] Dealing with the current time in reactive-banana

查看:101
本文介绍了处理反应香蕉中的当前时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你如何处理反应香蕉中的当前时间?



理想情况下,我希望有一个行为我可以轮询来获得当前时间。然而,使用事件 s轮询行为 s(通过< @ 等)给出了事件中的行为的值,不是当前值。 (我意识到这是为了避免循环定义,这确实有用。)



我发现 fromPoll 帮帮我。 fromPoll 观察到的行为 s不能依赖于它们自己,因此通过观察行为之前 之前 事件事件被触发而不是 >被解雇。



一个题外话



用一些更正式的术语来表示事件始终发生在时间 t + 行为始终在时间 t - Event 可以观察在它们之前发生的无限短时间的行为。由 accumB 和朋友生成的行为的新值始终始于时间 t +






$ 这个建议的语义行为 fromPoll 创建,它们会在每个 Event 被处理。其他行为 s将在之后更新,因为它们是由 accumB 和朋友创建的。



我的用例



无论如何,这是对我主要问题的一个重要的题外话。我想知道是否有一些方法可以处理当前时间(而不是前一个 事件)的时间无功香蕉。例如,我的用例是跟踪实体发送的ping,以及它们中的任何一个是否在特定时间间隔内未发送ping来发出警告事件的信号。



当然,我可以并且会很频繁地发起事件,所以我的警告不会有很大的错误。然而,它似乎是一个疣,他们不可能是确切的。



什么是正确的方式处理这个?

解决方案

考虑到您的示例用例,如果远离 fromPoll ,我认为您应该没问题。为了解释为什么,需要一些澄清。 (注意:在下面的内容中,stream指的是一个事件ta ,以及构成它们的其中一个发射的发生。)


然而,使用事件轮询Behaviors(通过< @ 等)给了我Behavior以前的事件,而不是当前值。


我想你是在暗指诸如此类的解释,从 stepper


请注意,比较中的小于符号 timex<时间意味着行为的价值在事件发生后略微改变。这允许递归定义。

然而,这种延迟仅与用于定义行为的流(即,你传给步进器 / accumB )以及与之同步的任何流。例如,假设您有两个独立的流, eTick eTock ,以及以下网络片段:

  eIncrement =(+1)< $ eTick 
bCount = accumB 0 eIncrement
eCountTick = bCount< @ eTick

eCountTock = bCount< @ eTock

eIncrement eCountTick eTick 同步,所以通过 eCountTick 是旧值;也就是同步更新之前的值。然而,从 eCountTock 给出的观点来看,这些都不重要。对于使用 eCountTock 的观察者来说,没有任何延迟可言,并且该值始终是当前值。


fromPoll 观察到的行为不能依赖于它们自己,因此在之前观察行为没有引入周期>此事件在上一次事件触发后被解雇,而不仅仅是


我们只关心流与更新行为的同步。因此,就观测值而言,就在下一次出现之前和刚刚出现之前就归结为同样的事情。 fromPoll ,然而,混乱的事情相当多。它会创建一个行为,在事件网络中发生任何事件时都会更新该行为;所以更新与所有流的联合同步。没有独立于 fromPoll 事件的流,因此观察值将受到延迟的影响,但我们观察到它。因此, fromPoll 不适用于应用程序驱动时钟,它需要以一定的准确度跟踪连续变化。



隐含在上述所有内容中,反应性香蕉没有固有的时间观念。每个流中只有逻辑时间线,可以通过合并流来交织。所以如果我们想要一个当前的时间行为,我们最好的选择就是从独立的流中构建一个。这是一个这种方法的演示,只要 threadDelay 的精度允许:

  { - #LANGUAGE RankNTypes# - } 
模块Main其中

导入Control.Concurrent
导入Control.Monad
import Data.Time
import Reactive.Banana
import Reactive.Banana.Frameworks

main = do
let netDesc :: forall t。框架t => Moment t()
netDesc = do
(eTime,fireTime)< - newEvent
liftIO。 forkIO。永远$
threadDelay(50 * 1000)>> getCurrentTime>> = fireTime
bTime< - 翻转步进器eTime< $> liftIO getCurrentTime
(eTick,fireTick)< - newEvent
liftIO。 forkIO。永远$
threadDelay(5000 * 1000)>> fireTick()
reactimate $ print< $> bTime< @ eTick
network< - 编译netDesc
致动网络>> threadDelay(52000 * 1000)>>暂停网络

bTime 通过 eTime 每个0.05s;通过 eTick 来观察,这是一个独立于 eTime 的流,每5秒发生一次。然后,您可以使用 eTick 和从它派生的流观察和更新您的实体。或者,您可以结合 bTime 和应用样式中的实体行为来获取,例如行为,以 eTick



观察最新ping的行为。规范的时间行为看起来像一个合理的方法在你的情况下;它在概念上是清楚的并且容易推广多个蜱。在任何情况下,您可以使用的其他方法包括摆脱 bTime 并使用 eTick 作为低分辨率目前的时间流(虽然这似乎使得 threadDelay innacurcies建立得更快),并通过使用 eTick 改变 ,从行为中获得新鲜更新的值(通过它自带的怪癖和烦恼,如文档提示)。

How do you deal with the current time in reactive-banana?

Ideally I'd like to have a Behaviour which I can "poll" to get the current time. However, polling Behaviours with Events (via <@ etc.) gives me the value of the Behaviour from the previous Event, not the current value. (I realise this is to avoid cyclic definitions which is indeed useful.)

I found fromPoll which I thought would help. Behaviours that are observed from fromPoll cannot depend on themselves, thus no cycles can be introduced by observing the behaviour just before this Event is fired rather than just after the previous Event fired.

A digression

In somewhat more formal terms I am suggesting that Events always occur at time t+ and Behaviours are always observed at time t- i.e. Events observe behaviours that happen an infinitessimally short time before them. New values of Behaviours generated by accumB and friends would always start from time t+ so could not be observed by Events which also happen at time t+.

Under this proposed semantics Behaviours created by fromPoll would be updated just before each Event is processed. Other Behaviours would be updated afterwards because they are created by accumB and friends.

My use case

Anyway, that's a significant digression to my main question. I want to know if there's some way to deal with current time (not the time of the previous Event) in reactive-banana. My use case is, for example, to keep track of the pings that entities send and if any of them hasn't sent a ping in a particular time interval to signal a warning event.

Of course I can and will fire off events very frequently, so my warnings won't be incorrect by a large amount. However it does seem to be a wart that they cannot be precise.

What's the right way of dealing with this?

解决方案

Given your example use case, I think you should be fine if you stay away from fromPoll. To explain why, a few clarifications are needed. (Note: in what follows, "stream" refers to an Event t a, and "occurrence" to one of the firings which compose them.)

However, polling Behaviours with Events (via <@ etc.) gives me the value of the Behaviour from the previous Event, not the current value.

I suppose you are alluding to explanations such as this one, from the docs for stepper:

Note that the smaller-than-sign in the comparision timex < time means that the value of the behavior changes "slightly after" the event occurrences. This allows for recursive definitions.

That delay, however, is only with respect to the stream used to define the behaviour (i.e. the one you pass to stepper/accumB) and any streams that are synchronised with it. For instance, suppose you have two independent streams, eTick and eTock, and the following network snippet:

eIncrement = (+1) <$ eTick
bCount = accumB 0 eIncrement
eCountTick = bCount <@ eTick

eCountTock = bCount <@ eTock

eIncrement and eCountTick are in sync with eTick, and so the value observed through eCountTick is the "old" value; that is, the value before the synchronised update. From the point of view given by eCountTock, however, none of that matters. To an observer using eCountTock, there is no delay to speak of, and the value is always the current one.

Behaviours that are observed from fromPoll cannot depend on themselves, thus no cycles can be introduced by observing the behaviour just before this Event is fired rather than just after the previous Event fired.

We are only concerned with streams synchronised with the one which updates the behaviour. Thus, as far as observed values go "just before the next occurrence" and "just after the previous occurrence" boil down to the same thing. fromPoll, however, muddles things quite a bit. It creates a behaviour which is updated whenever any occurrence happens in the event network; and so the updates are synchronised with the union of all streams. There is no such thing as a stream independent from a fromPoll event, and therefore the observed value will be affected by the delay however we observe it. That being so, fromPoll won't work for an application-driving clock, which requires tracking continuous change with some accuracy.

Implicit in all of the above is that reactive-banana has no built-in notion of time. There are only the "logical" time lines within each stream, which can be interwoven by merging streams. So if we want a current time behaviour our best bet is building one from an independent stream. Here is a demo of that approach, which will produce fresh and timely results as far as the precision of threadDelay allows:

{-# LANGUAGE RankNTypes #-}
module Main where

import Control.Concurrent
import Control.Monad
import Data.Time
import Reactive.Banana
import Reactive.Banana.Frameworks

main = do
    let netDesc :: forall t. Frameworks t => Moment t ()
        netDesc = do
            (eTime, fireTime) <- newEvent
            liftIO . forkIO . forever $
                threadDelay (50 * 1000) >> getCurrentTime >>= fireTime
            bTime <- flip stepper eTime <$> liftIO getCurrentTime
            (eTick, fireTick) <- newEvent
            liftIO . forkIO . forever $
                threadDelay (5000 * 1000) >> fireTick ()
            reactimate $ print <$> bTime <@ eTick
    network <- compile netDesc
    actuate network >> threadDelay (52000 * 1000) >> pause network

bTime is updated through eTime each 0.05s; it is observed through eTick, a stream independent from eTime with occurrences every 5s. You can then use eTick and streams derived from it to observe and update your entities. Alternatively, you can combine bTime and the entity behaviours in applicative style to get, e.g. behaviours for the latest pings, to be observed with eTick.

Having a canonical time behaviour looks like a sound approach in your case; it is conceptually clear and readily generalisable for multiple ticks. In any case, other approaches that you can play with include getting rid of bTime and using eTick as a low-resolution current time stream (though that seems to make the threadDelay innacurcies build up faster), and getting rid of eTick by using changes to get a stream of freshly updated values from the behaviour (through that comes with its own quirks and annoyances, as the documentation hints at).

这篇关于处理反应香蕉中的当前时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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