Ticket #66: Frip.hs

File Frip.hs, 6.8 KB (added by pesco, 7 years ago)

demo prototype demonstrating the approach

Line 
1{-# OPTIONS_GHC -fglasgow-exts -farrows #-}
2
3import Control.Arrow
4import Data.Word (Word32)
5import Prelude hiding (id, const)
6
7import System.Time
8import Control.Concurrent (forkIO, threadDelay, myThreadId, killThread)
9import Control.Concurrent.STM
10import Control.Exception (throwDynTo, catchDyn)
11import Control.Monad (unless, when)
12import Control.Monad.Fix (fix)
13import Data.Typeable
14import Data.Maybe (isJust)
15
16
17type Time   = Integer   -- microseconds, leaves 64 bits after ~500,000 years
18type DTime  = Word32    -- microseconds, wraps around after about one hour
19
20sleepmax = maxBound `div` 2 :: DTime
21
22secs :: (Integral a, Fractional b) => a -> b    -- assuming argument in microseconds
23secs usecs = fromIntegral usecs / 1000000
24
25type Event a = Maybe a
26
27
28newtype SF a b = SF (DTime -> a -> Bool -> DTime -> (SF a b, b, Bool, DTime))
29
30instance Arrow SF where
31  arr f = SF sf
32    where
33    sf _ x i s = (SF sf, f x, i, s)
34
35  SF f >>> SF g = SF h
36    where
37    h dt x i s = (f' >>> g', z, k, r)
38      where
39      (f', y, j, t)  = f dt x i s
40      (g', z, k, r)  = g dt y j t
41
42  first (SF f) = SF g
43    where
44    g dt (x,z) i s = (first f', (y,z), j&&i, if t==0 then 0 else min t s)
45      where
46      (f', y, j, t) = f dt x i s
47
48  second (SF f) = SF g
49    where
50    g dt (z,x) i s = (second f', (z,y), j&&i, if t==0 then 0 else min t s)
51      where
52      (f', y, j, t) = f dt x i s
53
54  SF f *** SF g = SF h
55    where
56    h dt (a,b) i s = (f' *** g', (x,y), j && k, min t r)
57      where
58      (f', x, j, t)  = f dt a i s
59      (g', y, k, r)  = g dt b i s
60
61  SF f &&& SF g = SF h
62    where
63    h dt x i s = (f' &&& g', (y,z), j && k, min t r)
64      where
65      (f', y, j, t)  = f dt x i s
66      (g', z, k, r)  = g dt x i s
67
68id :: Arrow a => a b b
69id = arr (\x -> x)
70
71const :: b -> SF a b
72const x = SF $ \_ _ _ _ -> (const x, x, True, sleepmax)
73
74
75instance ArrowLoop SF where
76  loop (SF f) = SF g
77    where
78    g dt x i s = (loop f', y, j, t)
79      where
80      (f', (y,z), j, t) = f dt (x,z) False 0  -- must avoid non-termination
81                                              -- of (i&&j) (min s t)
82
83loopre :: c -> SF (a,c) (b,c) -> SF a b
84loopre z0 sf = loop' (second (ipre z0) >>> sf)
85  where
86  loop' (SF f) = SF g
87    where
88    g dt x i s = (loop' f', y, j, t)
89      where
90      (f', (y,z), j, t) = f dt (x,z) (i&&j) (min s t)  -- can afford it here,
91                                                       -- because of the pre
92
93
94time :: SF a Time
95time = dtime >>> loopre 0 (arr (\(dt,t) -> let t'=t+fromIntegral dt in (t',t'))) --integ 0
96  where
97  integ s = SF $ \dt _ _ _ -> (integ (s+fromIntegral dt), s, False, 0)
98
99dtime = SF $ \dt _ _ _ -> (dtime, dt, False, 0)
100
101integral :: Fractional a => SF a a
102integral = integ 0
103  where
104  integ s = SF $ \dt x _ _ -> (integ (s+secs dt*x), s, False, 0)
105
106
107(-->) :: b -> SF a b -> SF a b
108y0 --> SF f = SF g
109  where
110  g dt x i s = (f', y0, False, 0)
111    where
112    (f', _, _, _) = f dt x i s
113
114(>--) :: a -> SF a b -> SF a b
115x0 >-- SF f = SF (\dt _ _ _ -> f dt x0 False 0)
116
117(>=-) :: (a -> a) -> SF a b -> SF a b
118g >=- SF f = SF (\dt x _ _ -> f dt (g x) False 0)
119
120pre :: SF a a
121pre = ipre (error "Frip: pre: uninitialized")
122
123ipre :: a -> SF a a
124ipre x0 = SF (f x0 False 0)
125  where
126  f x i s  dt y j t  = (SF (f y j t), x, i, s)
127
128
129switch :: SF a (b, Event c) -> (c -> SF a b) -> SF a b
130switch (SF f) k = SF g
131  where
132  g dt x i s = case e of  Nothing  -> (switch g' k, y, j, t)
133                          Just z   -> let SF kz = k z in kz dt x i s
134    where
135    (g', (y,e), j, t) = f dt x i s
136
137rswitch :: SF a b -> SF (a, Event (SF a b)) b
138rswitch f = switch (first f) (\g -> (\(x,e) -> (x,Nothing)) >=- rswitch g)
139
140accumby :: (b -> a -> b) -> b -> SF (Event a) (Event b)
141accumby f y0 = switch (never &&& id) $ \x -> aux (f y0 x)
142  where
143  aux y = switch (now y &&& notnow) $ \x -> aux (f y x)
144
145now :: b -> SF a (Event b)
146now y = Just y --> never
147
148notnow :: SF (Event a) (Event a)
149notnow = Nothing --> id
150
151never :: SF a (Event b)
152never = const Nothing
153
154hold :: a -> SF (Event a) a
155hold y0 = switch (const y0 &&& id) (\y -> Nothing >-- hold y)
156
157
158reactimate :: (DTime -> IO (Maybe a)) -> SF a b -> (b -> IO Bool) -> IO ()
159reactimate input (SF f0) output
160  = do  x0 <- fix (\f -> input sleepmax >>= maybe f return)
161        t0 <- getClockTime
162        let r = f0 0 x0 False sleepmax
163        loop x0 t0 r
164  where
165  loop x t (SF f, y, _, s)
166    = do  keep_running <- output y
167          when keep_running $
168            do  putStrLn "-00-"
169                putStrLn ("stable: " ++ show s)
170                m <- input s
171                putStrLn "-01-"
172                let  (x', idle) = maybe (x,True) (\y->(y,False)) m
173                t' <- getClockTime
174                let r = f (timediff t' t) x' idle sleepmax
175                x' `seq` idle `seq` putStrLn "-02-"
176                loop x' t' r
177
178timediff :: ClockTime -> ClockTime -> DTime
179timediff (TOD sec1 psec1) (TOD sec2 psec2)
180  = fromIntegral $ (sec1-sec2)*1000000 + ((psec1-psec2) `div` 1000000)
181
182data Wakeup = Wakeup deriving Typeable
183
184
185
186sf :: SF (Event String) String
187sf = proc ev -> do  cnt <- counter -< ev
188                    rswitch off -< (cnt, effswitch ev)
189  where
190  effswitch ev = case ev of  Just "sin"  -> Just sine
191                             Just "tim"  -> Just timedisp
192                             Just "dt"   -> Just dtdisp
193                             Just "cnt"  -> Just id
194                             Just "off"  -> Just off
195                             _           -> Nothing
196
197timedisp = time >>> arr (\t -> show (fromIntegral (t`div`10000) / 100) ++ "s")
198dtdisp = dtime >>> arr (\dt -> show dt ++ "us")
199
200off = const "<off>"
201
202sine = time >>> arr f
203  where
204  f x = replicate (round (20 + 20 * sin (fromIntegral x / 1000000 * pi)))  '~'
205
206counter = accumby (\n _ -> n+1) 0 >>> hold 0 >>> arr show
207
208
209main = do  inp <- atomically (newTMVar Nothing)
210           forkIO $ fix $ \f -> do  x <- getLine
211                                    atomically (putTMVar inp (Just x))
212                                    f
213           reactimate (input inp) sf (\x -> putStrLn x >> return True)
214
215input inp timo
216  | False = undefined  -- timo==0    = atomically trygetev
217  | otherwise  = do  alm <- atomically (newTVar False)
218                     putStrLn ("timo: " ++ show timo)
219                     forkIO $ do  threadDelay (fromIntegral timo)
220                                  atomically (writeTVar alm True)
221                     atomically (getevent `orElse` waitfor alm)
222  where
223  getevent  = do  x <- takeTMVar inp
224                  when (isJust x) (putTMVar inp Nothing)
225                  return (Just x)
226  trygetev  = do  mx <- tryTakeTMVar inp
227                  maybe  (return Nothing)
228                         (\x -> do  when (isJust x) (putTMVar inp Nothing)
229                                    return (Just x))
230                         mx
231  waitfor alm = do  b <- readTVar alm
232                    if b  then  return Nothing
233                          else  retry