2012-06-04 27 views
7

मैं प्रतिक्रियाशील केले में घटनाओं के एक निश्चित प्रकार के थ्रॉटलिंग को कार्यान्वित करना चाहता हूं। यह इस तरह काम करना चाहिए कि अगर घटना से गुज़रने वाली आखिरी घटना से डेल्टा सेकेंड कम हो तो एक घटना नहीं दी जाती है। यदि इसे तब तक नहीं छोड़ा जाता है, तो इसे संग्रहीत किया जाता है और आखिरी निकाल दिया गया ईवेंट से डेल्टा सेकेंड के बाद निकाल दिया जाता है।प्रतिक्रियाशील-केला थ्रॉटलिंग घटनाएं

नीचे एक ऐसा प्रोग्राम है जो समयबद्ध मुद्रित संख्याओं की सूचियों के लिए इसे लागू करता है। क्या प्रतिक्रियाशील-केले में इसका अनुवाद करना संभव होगा?

इसके अलावा, प्रतिक्रियाशील-केले में मैं किसी अन्य घटना के बाद एक घटना 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

ठीक है, मैंने अपने प्रश्न में जो वर्णन किया है उसे लागू करने में कामयाब रहा। मैं इतना खुश नहीं हूं कि आईओ को प्रतिक्रिया के माध्यम से टाइमर को नियंत्रित करने की आवश्यकता है। मुझे आश्चर्य है कि अगर यह हस्ताक्षर थ्रोटल के साथ एक थ्रोटल :: घटना टा करने के लिए संभव हो जाएगा -> इंट -> घटना टा ...

ps: मैं हास्केल तो कोड सकता है शायद एक बहुत अधिक कॉम्पैक्ट में बहुत नौसिखिया हूँ या सुरुचिपूर्ण।

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

------------------------------------------------------------------------------} 
{-# 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 
+1

आप आईओ से खुश नहीं हैं, तो आप कुछ है कि संदेशों वाली एक घटना को सुनता है के रूप में टाइमर लागू कर सकते हैं ("शुरू", "बंद करो", "रीसेट") और एक अन्य घटना देता है। आम तौर पर, मैं उन कार्यों को रखने की अनुशंसा करता हूं जो 'नेटवर्कडिस्क्रिप्शन' मोनैड में 'रिएक्टिम' का उपयोग करते हैं, यानी 'थ्रॉटल :: ... -> नेटवर्क थ्रॉटल टी (इवेंट टा) '' थ्रॉटल :: .. -> (इवेंट टा, नेटवर्क डिस्क्रिप्शन टी()) '। –

+0

ठीक है, जो इसे वास्तव में बहुत साफ बनाता है और वाक्यविन्यास के मामले में थ्रॉटल :: इवेंट टी ए -> इंट -> इवेंट टी ए (केवल उपयोग करें <- डू कथन में जाने के बजाय) से बहुत अलग नहीं है। मैंने आपके सुझाव के साथ पुनः कार्यान्वित किया है: https://gist.github.com/2905841। मुझे लगता है कि मैं इस समाधान से बहुत खुश हूं। –

3

प्रतिक्रियाशील-केले 0.6 के रूप में, यह निश्चित रूप से आप की इच्छा कार्यक्षमता लागू करने के लिए संभव है, लेकिन यह एक छोटे से शामिल है।

असल में, आपने टाइमर बनाने के लिए WxHaskell जैसे बाहरी ढांचे का उपयोग किया है, जिसका उपयोग आप ईवेंट शेड्यूल करने के लिए कर सकते हैं। Wave.hs उदाहरण दर्शाता है कि यह कैसे करें।

फिलहाल, मैंने प्रतिक्रियाशील-केले पुस्तकालय में समय की धारणा शामिल नहीं करने का विकल्प चुना है। कारण यह है कि अलग-अलग बाहरी ढांचे में अलग-अलग रिज़ॉल्यूशन या गुणवत्ता के टाइमर होते हैं, कोई भी आकार नहीं है जो इसे फिट करता है।

मैं पुस्तकालय में समय और टाइमर के साथ सौदा करने वाले सामान्य सहायक कार्यों को जोड़ने का इरादा रखता हूं, लेकिन मुझे अभी भी अलग-अलग टाइमर पर सामान्य बनाने के लिए एक अच्छा तरीका खोजने की आवश्यकता है और यह पता लगाने के लिए कि मैं कौन सी गारंटी प्रदान कर सकता हूं।

संबंधित मुद्दे