| 1 | {-# OPTIONS_GHC -fglasgow-exts -farrows #-} |
|---|
| 2 | |
|---|
| 3 | import Control.Arrow |
|---|
| 4 | import Data.Word (Word32) |
|---|
| 5 | import Prelude hiding (id, const) |
|---|
| 6 | |
|---|
| 7 | import System.Time |
|---|
| 8 | import Control.Concurrent (forkIO, threadDelay, myThreadId, killThread) |
|---|
| 9 | import Control.Concurrent.STM |
|---|
| 10 | import Control.Exception (throwDynTo, catchDyn) |
|---|
| 11 | import Control.Monad (unless, when) |
|---|
| 12 | import Control.Monad.Fix (fix) |
|---|
| 13 | import Data.Typeable |
|---|
| 14 | import Data.Maybe (isJust) |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | type Time = Integer -- microseconds, leaves 64 bits after ~500,000 years |
|---|
| 18 | type DTime = Word32 -- microseconds, wraps around after about one hour |
|---|
| 19 | |
|---|
| 20 | sleepmax = maxBound `div` 2 :: DTime |
|---|
| 21 | |
|---|
| 22 | secs :: (Integral a, Fractional b) => a -> b -- assuming argument in microseconds |
|---|
| 23 | secs usecs = fromIntegral usecs / 1000000 |
|---|
| 24 | |
|---|
| 25 | type Event a = Maybe a |
|---|
| 26 | |
|---|
| 27 | |
|---|
| 28 | newtype SF a b = SF (DTime -> a -> Bool -> DTime -> (SF a b, b, Bool, DTime)) |
|---|
| 29 | |
|---|
| 30 | instance 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 | |
|---|
| 68 | id :: Arrow a => a b b |
|---|
| 69 | id = arr (\x -> x) |
|---|
| 70 | |
|---|
| 71 | const :: b -> SF a b |
|---|
| 72 | const x = SF $ \_ _ _ _ -> (const x, x, True, sleepmax) |
|---|
| 73 | |
|---|
| 74 | |
|---|
| 75 | instance 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 | |
|---|
| 83 | loopre :: c -> SF (a,c) (b,c) -> SF a b |
|---|
| 84 | loopre 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 | |
|---|
| 94 | time :: SF a Time |
|---|
| 95 | time = 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 | |
|---|
| 99 | dtime = SF $ \dt _ _ _ -> (dtime, dt, False, 0) |
|---|
| 100 | |
|---|
| 101 | integral :: Fractional a => SF a a |
|---|
| 102 | integral = 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 |
|---|
| 108 | y0 --> 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 |
|---|
| 115 | x0 >-- SF f = SF (\dt _ _ _ -> f dt x0 False 0) |
|---|
| 116 | |
|---|
| 117 | (>=-) :: (a -> a) -> SF a b -> SF a b |
|---|
| 118 | g >=- SF f = SF (\dt x _ _ -> f dt (g x) False 0) |
|---|
| 119 | |
|---|
| 120 | pre :: SF a a |
|---|
| 121 | pre = ipre (error "Frip: pre: uninitialized") |
|---|
| 122 | |
|---|
| 123 | ipre :: a -> SF a a |
|---|
| 124 | ipre 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 | |
|---|
| 129 | switch :: SF a (b, Event c) -> (c -> SF a b) -> SF a b |
|---|
| 130 | switch (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 | |
|---|
| 137 | rswitch :: SF a b -> SF (a, Event (SF a b)) b |
|---|
| 138 | rswitch f = switch (first f) (\g -> (\(x,e) -> (x,Nothing)) >=- rswitch g) |
|---|
| 139 | |
|---|
| 140 | accumby :: (b -> a -> b) -> b -> SF (Event a) (Event b) |
|---|
| 141 | accumby 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 | |
|---|
| 145 | now :: b -> SF a (Event b) |
|---|
| 146 | now y = Just y --> never |
|---|
| 147 | |
|---|
| 148 | notnow :: SF (Event a) (Event a) |
|---|
| 149 | notnow = Nothing --> id |
|---|
| 150 | |
|---|
| 151 | never :: SF a (Event b) |
|---|
| 152 | never = const Nothing |
|---|
| 153 | |
|---|
| 154 | hold :: a -> SF (Event a) a |
|---|
| 155 | hold y0 = switch (const y0 &&& id) (\y -> Nothing >-- hold y) |
|---|
| 156 | |
|---|
| 157 | |
|---|
| 158 | reactimate :: (DTime -> IO (Maybe a)) -> SF a b -> (b -> IO Bool) -> IO () |
|---|
| 159 | reactimate 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 | |
|---|
| 178 | timediff :: ClockTime -> ClockTime -> DTime |
|---|
| 179 | timediff (TOD sec1 psec1) (TOD sec2 psec2) |
|---|
| 180 | = fromIntegral $ (sec1-sec2)*1000000 + ((psec1-psec2) `div` 1000000) |
|---|
| 181 | |
|---|
| 182 | data Wakeup = Wakeup deriving Typeable |
|---|
| 183 | |
|---|
| 184 | |
|---|
| 185 | |
|---|
| 186 | sf :: SF (Event String) String |
|---|
| 187 | sf = 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 | |
|---|
| 197 | timedisp = time >>> arr (\t -> show (fromIntegral (t`div`10000) / 100) ++ "s") |
|---|
| 198 | dtdisp = dtime >>> arr (\dt -> show dt ++ "us") |
|---|
| 199 | |
|---|
| 200 | off = const "<off>" |
|---|
| 201 | |
|---|
| 202 | sine = time >>> arr f |
|---|
| 203 | where |
|---|
| 204 | f x = replicate (round (20 + 20 * sin (fromIntegral x / 1000000 * pi))) '~' |
|---|
| 205 | |
|---|
| 206 | counter = accumby (\n _ -> n+1) 0 >>> hold 0 >>> arr show |
|---|
| 207 | |
|---|
| 208 | |
|---|
| 209 | main = 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 | |
|---|
| 215 | input 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 |
|---|