1 {-# LANGUAGE Arrows, FlexibleContexts, MultiParamTypeClasses #-}
3 -- | Auxiliary functions used throughout the code.
4 module RMCA.Auxiliary where
8 import qualified Data.IntMap as M
10 import Data.ReactiveValue
13 -- |= General functions
16 -- | Reversed version of '(\<$\>)'.
17 (<$$>) :: (Functor f) => f a -> (a -> b) -> f b
20 -- | Reversed version of '(<$)'.
21 ($>) :: (Functor f) => f a -> b -> f b
24 -- | @bound (min,max)@ behaves like identity if the supplied value is between @min@ and @max@, otherwise it is replaced either by @min@ or by @max@.
25 bound :: (Ord a) => (a, a) -> a -> a
31 fromMaybeM_ :: (Monad m) => Maybe (m ()) -> m ()
32 fromMaybeM_ = fromMaybe (return ())
34 safeHead :: [a] -> Maybe a
36 safeHead (x:_) = Just x
38 safeTail :: [a] -> [a]
42 maybeToEvent :: Maybe a -> Event a
43 maybeToEvent Nothing = NoEvent
44 maybeToEvent (Just x) = Event x
46 eventToMaybe :: Event a -> Maybe a
47 eventToMaybe NoEvent = Nothing
48 eventToMaybe (Event x) = Just x
50 eventToList :: Event [a] -> [a]
51 eventToList NoEvent = []
52 eventToList (Event x) = x
54 -- | Generates an 'Event' if the given condition is 'True'.
55 eventIf :: Bool -> Event ()
56 eventIf b = if b then Event () else NoEvent
58 -- | Generates a 'Just' value if the given condition is 'True'.
59 maybeIf :: Bool -> Maybe ()
60 maybeIf b = if b then Just () else Nothing
62 intersectionWith3 :: (a -> b -> c -> d)
67 intersectionWith3 f m n p =
68 M.intersectionWith (\x (y,z) -> f x y z) m $ M.intersectionWith (,) n p
72 countTo :: (Integral b, Ord b) => b -> SF (Event a) (Event b)
73 countTo n = count >>^ filterE (> n)
75 -- | 'stepBack' contains its previous argument as its output. Because it's hard to define it at time 0, it's wrapped up in a 'Maybe'.
76 stepBack :: SF a (Maybe a)
77 stepBack = sscan f (Nothing, Nothing) >>^ snd
78 where f :: (Maybe a, Maybe a) -> a -> (Maybe a, Maybe a)
79 f (Nothing,_) x' = (Just x', Nothing)
80 f (Just x, _) x' = (Just x', Just x)
82 -- | Like 'stepBack' but the output value is always defined and is equal to the input at time 0.
84 stepBack' = proc x -> do
86 returnA -< fromMaybe x x'
88 -- | Throws an 'Event' when the incoming signal change. The 'Event' is tagged with the new value.
89 onChange :: (Eq a) => SF a (Event a)
90 onChange = proc x -> do
93 | isNothing x' = NoEvent
94 | otherwise = let x'' = fromJust x' in
95 if x'' == x then NoEvent else Event x
96 returnA -< makeEvent x x'
98 -- | Similar to 'onChange' but contains its initial value in the first
100 onChange' :: (Eq a) => SF a (Event a)
101 onChange' = proc x -> do
103 -- If it's the first value, throw an Event, else behave like onChange.
105 | isNothing x' = Event x
106 | otherwise = let x'' = fromJust x' in
107 if x'' == x then NoEvent else Event x
108 returnA -< makeEvent x x'
110 -- | Integrates some variable modulo something.
111 integralMod :: (Real a, VectorSpace a s) => a -> SF a a
112 integralMod x = intMod' 0
113 where intMod' x0 = switch (intMod'' x0) (\y -> intMod' (y - x))
114 intMod'' x0 = proc t -> do
115 it <- (+ x0) ^<< integral -< t
116 es <- edgeBy (\_ y -> maybeIf (y > x) $> y) 0 -< it
121 -- | Generates a sine function whose period is given as a varying input.
122 varFreqSine :: SF DTime Double
123 varFreqSine = sin ^<< (2*pi*) ^<< integralMod 1 <<^ (1/)
125 -- | Generates an 'Event' with a regular period, which is given as an input to the signal function.
126 repeatedlyS :: a -> SF DTime (Event a)
127 repeatedlyS x = edgeBy (\a b -> maybeIf (a * b < 0) $> x) 0
128 <<< varFreqSine <<^ (2*)
131 -- = Auxiliary functions for manipulating reactive values
133 -- | Creates a new 'CBMVar' wrapped into a reactive field.
134 newCBMVarRW :: a -> IO (ReactiveFieldReadWrite IO a)
136 mvar <- newCBMVar val
137 let getter = readCBMVar mvar
138 setter = writeCBMVar mvar
139 notifier = installCallbackCBMVar mvar
140 return $ ReactiveFieldReadWrite setter getter notifier
142 -- | Appends a value to a reactive value.
143 reactiveValueAppend :: (Monoid b, ReactiveValueReadWrite a b m) =>
145 reactiveValueAppend rv v = do ov <- reactiveValueRead rv
146 reactiveValueWrite rv (ov `mappend` v)
148 -- | Writes 'mempty' to a reactive value containing a 'Monoid'.
149 reactiveValueEmpty :: (Monoid b, ReactiveValueReadWrite a b m) =>
151 reactiveValueEmpty rv = reactiveValueWrite rv mempty
153 -- | Writes a value to a reactive value if the value is different from the one already in the reactive value.
154 reactiveValueWriteOnNotEq :: ( Eq b
155 , ReactiveValueReadWrite a b m) =>
157 reactiveValueWriteOnNotEq rv nv = do
158 ov <- reactiveValueRead rv
159 when (ov /= nv) $ reactiveValueWrite rv nv
161 -- | Relation that will update when the value is an 'Event'.
162 (>:>) :: (ReactiveValueRead a (Event b) IO, ReactiveValueWrite c b IO) =>
164 eventRV >:> rv = reactiveValueOnCanRead eventRV syncOnEvent
165 where syncOnEvent = do
166 erv <- reactiveValueRead eventRV
167 when (isEvent erv) $ reactiveValueWrite rv $ fromEvent erv
169 -- | When the reactive value on the left changes, the value on the right is updated using the value it contains and the value on the left with the provided function.
170 syncRightOnLeftWithBoth :: ( ReactiveValueRead a b m
171 , ReactiveValueReadWrite c d m
172 ) => (b -> d -> d) -> a -> c -> m ()
173 syncRightOnLeftWithBoth f l r = reactiveValueOnCanRead l $ do
174 nl <- reactiveValueRead l
175 or <- reactiveValueRead r
176 reactiveValueWrite r (f nl or)
178 -- | Forces to update an reactive value by writing to it with the value it contains.
179 updateRV :: (ReactiveValueReadWrite a b m) => a -> m ()
180 updateRV rv = reactiveValueRead rv >>= reactiveValueWrite rv
183 , ReactiveValueWrite a b m
184 , ReactiveValueWrite c d m
185 , ReactiveValueWrite e f m) =>
186 (i -> (b,d,f)) -> a -> c -> e -> ReactiveFieldWrite m i
187 liftW3 f a b c = ReactiveFieldWrite setter
190 reactiveValueWrite a x1
191 reactiveValueWrite b x2
192 reactiveValueWrite c x3
194 liftRW3 :: ( ReactiveValueReadWrite a b m
195 , ReactiveValueReadWrite c d m
196 , ReactiveValueReadWrite e f m) =>
197 BijectiveFunc i (b,d,f) -> a -> c -> e -> ReactiveFieldReadWrite m i
199 ReactiveFieldReadWrite setter getter notifier
200 where ReactiveFieldRead getter notifier = liftR3 (curry3 f2) a b c
201 ReactiveFieldWrite setter = liftW3 f1 a b c
202 (f1, f2) = (direct bij, inverse bij)
204 liftR4 :: ( ReactiveValueRead a b m
205 , ReactiveValueRead c d m
206 , ReactiveValueRead e f m
207 , ReactiveValueRead g h m) =>
208 (b -> d -> f -> h -> i) -> a -> c -> e -> g -> ReactiveFieldRead m i
209 liftR4 f a b c d = ReactiveFieldRead getter notifier
211 x1 <- reactiveValueRead a
212 x2 <- reactiveValueRead b
213 x3 <- reactiveValueRead c
214 x4 <- reactiveValueRead d
215 return $ f x1 x2 x3 x4
217 reactiveValueOnCanRead a p
218 reactiveValueOnCanRead b p
219 reactiveValueOnCanRead c p
220 reactiveValueOnCanRead d p
223 , ReactiveValueWrite a b m
224 , ReactiveValueWrite c d m
225 , ReactiveValueWrite e f m
226 , ReactiveValueWrite g h m) =>
227 (i -> (b,d,f,h)) -> a -> c -> e -> g -> ReactiveFieldWrite m i
228 liftW4 f a b c d = ReactiveFieldWrite setter
230 let (x1,x2,x3,x4) = f x
231 reactiveValueWrite a x1
232 reactiveValueWrite b x2
233 reactiveValueWrite c x3
234 reactiveValueWrite d x4
236 liftRW4 :: ( ReactiveValueReadWrite a b m
237 , ReactiveValueReadWrite c d m
238 , ReactiveValueReadWrite e f m
239 , ReactiveValueReadWrite g h m) =>
240 BijectiveFunc i (b,d,f,h) -> a -> c -> e -> g
241 -> ReactiveFieldReadWrite m i
242 liftRW4 bij a b c d =
243 ReactiveFieldReadWrite setter getter notifier
244 where ReactiveFieldRead getter notifier = liftR4 (curry4 f2) a b c d
245 ReactiveFieldWrite setter = liftW4 f1 a b c d
246 (f1, f2) = (direct bij, inverse bij)
248 liftR5 :: ( ReactiveValueRead a b m
249 , ReactiveValueRead c d m
250 , ReactiveValueRead e f m
251 , ReactiveValueRead g h m
252 , ReactiveValueRead i j m) =>
253 (b -> d -> f -> h -> j -> k) -> a -> c -> e -> g -> i
254 -> ReactiveFieldRead m k
255 liftR5 f a b c d e = ReactiveFieldRead getter notifier
257 x1 <- reactiveValueRead a
258 x2 <- reactiveValueRead b
259 x3 <- reactiveValueRead c
260 x4 <- reactiveValueRead d
261 x5 <- reactiveValueRead e
262 return $ f x1 x2 x3 x4 x5
264 reactiveValueOnCanRead a p
265 reactiveValueOnCanRead b p
266 reactiveValueOnCanRead c p
267 reactiveValueOnCanRead d p
268 reactiveValueOnCanRead e p
271 , ReactiveValueWrite a b m
272 , ReactiveValueWrite c d m
273 , ReactiveValueWrite e f m
274 , ReactiveValueWrite g h m
275 , ReactiveValueWrite i j m) =>
276 (k -> (b,d,f,h,j)) -> a -> c -> e -> g -> i -> ReactiveFieldWrite m k
277 liftW5 f a b c d e = ReactiveFieldWrite setter
279 let (x1,x2,x3,x4,x5) = f x
280 reactiveValueWrite a x1
281 reactiveValueWrite b x2
282 reactiveValueWrite c x3
283 reactiveValueWrite d x4
284 reactiveValueWrite e x5
286 liftRW5 :: ( ReactiveValueReadWrite a b m
287 , ReactiveValueReadWrite c d m
288 , ReactiveValueReadWrite e f m
289 , ReactiveValueReadWrite g h m
290 , ReactiveValueReadWrite i j m) =>
291 BijectiveFunc k (b,d,f,h,j) -> a -> c -> e -> g -> i
292 -> ReactiveFieldReadWrite m k
293 liftRW5 bij a b c d e =
294 ReactiveFieldReadWrite setter getter notifier
295 where ReactiveFieldRead getter notifier = liftR5 (curry5 f2) a b c d e
296 ReactiveFieldWrite setter = liftW5 f1 a b c d e
297 (f1, f2) = (direct bij, inverse bij)
300 -- = Curry and uncurry functions
302 curry3 :: ((a,b,c) -> d) -> a -> b -> c -> d
303 curry3 f a b c = f (a,b,c)
305 uncurry3 :: (a -> b -> c -> d) -> (a,b,c) -> d
306 uncurry3 f (a,b,c) = f a b c
308 curry4 :: ((a,b,c,d) -> e) -> a -> b -> c -> d -> e
309 curry4 f a b c d = f (a,b,c,d)
311 uncurry4 :: (a -> b -> c -> d -> e) -> (a,b,c,d) -> e
312 uncurry4 f (a,b,c,d) = f a b c d
314 curry5 :: ((a,b,c,d,e) -> f) -> a -> b -> c -> d -> e -> f
315 curry5 f a b c d e = f (a,b,c,d,e)
317 uncurry5 :: (a -> b -> c -> d -> e -> f) -> (a,b,c,d,e) -> f
318 uncurry5 f (a,b,c,d,e) = f a b c d e