Haskell 反应性香蕉节流事件

Haskell 反应性香蕉节流事件,haskell,reactive-programming,frp,Haskell,Reactive Programming,Frp,我想在反应式香蕉中实现某种类型的事件限制。它的工作原理应该是,如果某个事件在距离最后一个通过的事件不到增量秒的时间内到达,则该事件不会通过。如果未让其通过,则会存储它,并在上次触发事件的增量秒后触发 下面是一个为时间戳编号列表实现此功能的程序。有没有可能把这个翻译成反应性香蕉 另外,在反应式香蕉中,如何在其他事件发生后x秒触发事件 module Main where import Data.List -- 1 second throtling -- logic is to never out

我想在反应式香蕉中实现某种类型的事件限制。它的工作原理应该是,如果某个事件在距离最后一个通过的事件不到增量秒的时间内到达,则该事件不会通过。如果未让其通过,则会存储它,并在上次触发事件的增量秒后触发

下面是一个为时间戳编号列表实现此功能的程序。有没有可能把这个翻译成反应性香蕉

另外,在反应式香蕉中,如何在其他事件发生后x秒触发事件

module Main where import Data.List -- 1 second throtling -- logic is to never output a value before 1 second has passed since last value was outputed. main :: IO() main = print $ test [ (0.0, 1.0), (1.1, 2.0), (1.5,3.0), (1.7,4.0), (2.2, 5.0) ] --should output [ (0.0, 1.0), (1.1, 2.0), (2.1,4.0), (3.1, 5.0) ] test :: [(Double,Double)] -> [(Double,Double)] test list = g v (concat xs) where (v, xs) = mapAccumL f (-50,Nothing) list g (t, Just x) ys = ys ++ [ (t+1,x) ] g _ ys = ys f (lasttime, Just holdvalue) (t,x) = if t > (lasttime+1) then if t > (lasttime + 2) then ( (t, Nothing), [ (lasttime+1,holdvalue), (t,x)] ) else ( (lasttime+1, Just x) , [ (lasttime+1,holdvalue) ] ) else ( (lasttime, Just x), [] ) f (lasttime, Nothing) (t,x) = if t > (lasttime+1) then ( (t,Nothing) , [ (t, x ) ] ) else ( (lasttime, Just x), [] ) 模块主要在哪里 导入数据。列表 --1秒钟的抽搐 --逻辑是在自最后一个值输出后经过1秒之前决不输出值。 main::IO() main=print$test[(0.0,1.0),(1.1,2.0),(1.5,3.0),(1.7,4.0),(2.2,5.0)] --应该输出[(0.0,1.0),(1.1,2.0),(2.1,4.0),(3.1,5.0)] 测试::[(双,双)]->[(双,双)] 测试列表=g v(concat xs) 哪里 (v,xs)=mapAccumL f(-50,无)列表 g(t,刚好x)ys=ys++[(t+1,x)] g_ys=ys f(lasttime,Just holdvalue)(t,x)=如果t>(lasttime+1),则 如果t>(lasttime+2),则 ((t,无),[(lasttime+1,holdvalue),(t,x)]) else((lasttime+1,仅x),[(lasttime+1,holdvalue)]) 其他的 ((上次,仅x),[]) f(lasttime,Nothing)(t,x)=如果t>(lasttime+1),则 ((t,无),[(t,x)]) else((上次,仅x),[])
从reactive-banana-0.6开始,实现您想要的功能是完全可能的,但这有点复杂

基本上,您已经使用了一个外部框架(如wxHaskell)来创建一个计时器,然后可以使用它来安排事件。这个例子演示了如何做到这一点

目前,我选择不在反应式香蕉库中包含时间概念。原因很简单,不同的外部框架具有不同分辨率或质量的计时器,没有一种尺寸适合所有的外部框架


我确实打算将处理时间和计时器的常用助手函数添加到库本身,但我仍然需要找到一种好方法,使其在不同计时器上通用,并找出我可以提供的保证。

好的,我设法实现了我在问题中描述的功能。我不太高兴需要IO通过reactimate控制计时器。我想知道是否可能有一个具有签名throttle::Event ta->Int->Event ta的throttle

ps:我是Haskell的新手,因此代码可能会更加紧凑或优雅

{-----------------------------------------------------------------------------

------------------------------------------------------------------------------}
{-# LANGUAGE ScopedTypeVariables #-} -- allows "forall t. NetworkDescription t"

import Graphics.UI.WX hiding (Event)
import Reactive.Banana
import Reactive.Banana.WX
import Data.Time

{-----------------------------------------------------------------------------
    Main
------------------------------------------------------------------------------}

data ThrottledValue a = FireStoredValue a | FireNowAndStartTimer a| HoldIt a | Stopped deriving Show
data ThrottledEvent a = TimerEvent | RealEvent a deriving Show

main = start $ do
    f   <- frame [text := "Countercesss"]
    sl1  <- hslider f False 0 100 []
    sl2  <- hslider f False 0 100 []
    set f [ layout := column 0 [widget sl1, widget sl2] ]
    t <- timer f []
    set t [ enabled := False ] 
    let networkDescription :: forall t. NetworkDescription t ()
        networkDescription = do
        slEv <- event0 sl1 command
        tick <- event0 t command 
        slB <- behavior sl1 selection
        let (throttledEv, reactimates) = throttle (slB <@ slEv) tick t 100
        reactimates
        reactimate $ fmap (\x ->  set sl2 [selection := x]) throttledEv       
    net <- compile networkDescription
    actuate net            

throttle::Event t a -> Event t () -> Timer -> Int -> (Event t a, NetworkDescription t () )    
throttle ev tick timer dt = (throttledEv, reactimates)
        where   
                all = union (fmap (\x-> RealEvent x) ev) (fmap (\x -> TimerEvent) tick)
                result = accumE Stopped $ fmap h all
                        where
                        h (RealEvent x) Stopped = FireNowAndStartTimer x
                        h TimerEvent Stopped = Stopped
                        h (RealEvent x) (FireNowAndStartTimer _) = HoldIt x
                        h TimerEvent (FireNowAndStartTimer _) = Stopped
                        h (RealEvent x) (HoldIt _) = HoldIt x
                        h (TimerEvent) (HoldIt y) = FireStoredValue y
                        h (RealEvent x) (FireStoredValue _) = HoldIt x
                        h (TimerEvent) (FireStoredValue _) = Stopped          
                start (FireStoredValue a) = Just $ resetTimer timer dt
                start (FireNowAndStartTimer a) = Just $ resetTimer timer dt
                start _ = Nothing  
                stop Stopped = Just $ stopTimer timer
                stop _ = Nothing  
                reactimates = do
                        reactimate $ filterJust $ fmap stop result   
                        reactimate $ filterJust $ fmap start result
                filterFired (FireStoredValue a) = Just a
                filterFired (FireNowAndStartTimer a) = Just a
                filterFired _ = Nothing
                throttledEv = filterJust $ fmap filterFired result                 

startTimer t dt = set t [ enabled := True, interval := dt ]
stopTimer t = set t [ enabled := False ]
resetTimer t dt = stopTimer t >> startTimer t dt
{-----------------------------------------------------------------------------
------------------------------------------------------------------------------}
{-#语言范围的TypeVariables#-}--允许“forall t.NetworkDescription t”
导入Graphics.UI.WX隐藏(事件)
进口香蕉
导入Reactive.Banana.WX
导入数据。时间
{-----------------------------------------------------------------------------
主要
------------------------------------------------------------------------------}
数据节流值a=FireStoredValue a | FireNow和StartTime a | HoldIt a |停止导出显示
数据节流事件a=TimerEvent | RealEvent a派生显示
main=start$do
f startTimer t dt

如果您对IO不满意,可以将计时器实现为侦听包含消息(“开始”、“停止”、“重置”)的事件并返回另一个事件的功能。通常,我建议将使用
reactimate
的函数放入
NetworkDescription
monad,即
throttle::…->网络描述t(事件t a)
而不是
节流阀::…->(Event ta,NetworkDescription t())
。好的,这确实使它更清晰,而且在语法方面与throttle::Event ta->Int->Event ta(只需使用