处理反应香蕉中的当前时间 [英] Dealing with the current time in reactive-banana
问题描述
你如何处理反应香蕉中的当前时间?
理想情况下,我希望有一个行为
我可以轮询来获得当前时间。然而,使用事件
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
不适用于应用程序驱动时钟,它需要以一定的准确度跟踪连续变化。
隐含在上述所有内容中,反应性香蕉没有固有的时间观念。每个流中只有逻辑时间线,可以通过合并流来交织。所以如果我们想要一个当前的时间行为,我们最好的选择就是从独立的流中构建一个。这是一个这种方法的演示,只要
{ - #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
和应用样式中的实体行为来获取,例如行为,以
观察最新ping的行为。规范的时间行为看起来像一个合理的方法在你的情况下;它在概念上是清楚的并且容易推广多个蜱。在任何情况下,您可以使用的其他方法包括摆脱 Ideally I'd like to have a I found In somewhat more formal terms I am suggesting that Under this proposed semantics 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 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 However, polling Behaviours with Events (via I suppose you are alluding to explanations such as this one, from the docs for Note that the smaller-than-sign in the comparision That delay, however, is only with respect to the stream used to define the behaviour (i.e. the one you pass to Behaviours that are observed from 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. 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 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 这篇关于处理反应香蕉中的当前时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! bTime
并使用 eTick
作为低分辨率目前的时间流(虽然这似乎使得 threadDelay
innacurcies建立得更快),并通过使用改变
,从行为中获得新鲜更新的值(通过它自带的怪癖和烦恼,如文档提示)。 How do you deal with the current time in reactive-banana?
Behaviour
which I can "poll" to get the current time. However, polling Behaviour
s with Event
s (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.)fromPoll
which I thought would help. Behaviour
s 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
Event
s always occur at time t+ and Behaviours
are always observed at time t- i.e. Event
s observe behaviours that happen an infinitessimally short time before them. New values of Behaviour
s generated by accumB
and friends would always start from time t+ so could not be observed by Event
s which also happen at time t+.Behaviour
s created by fromPoll
would be updated just before each Event
is processed. Other Behaviour
s would be updated afterwards because they are created by accumB
and friends.My use case
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.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.)
<@
etc.) gives me the value of the Behaviour from the previous Event, not the current value.stepper
:
timex < time
means that the value of the behavior changes "slightly after" the event occurrences. This allows for recursive definitions.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.
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.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.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
.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).