{-# OPTIONS -fplugin=Rattus.Plugin #-}

-- | Programming with many-shot events, i.e. events that may occur zero
-- or more times.


module Rattus.Events
  ( map
  , never
  , switch
  , switchTrans
  , Events
  , trigger
  , triggerMap
  )

where

import Rattus
import Rattus.Stream hiding (map)
import qualified Rattus.Stream as S

import Prelude hiding ((<*>), map)

-- | Events are simply streams of 'Maybe''s.
type Events a = Str (Maybe' a)

-- all functions in this module are in Rattus 
{-# ANN module Rattus #-}

-- | Apply a function to the values of the event (every time it occurs).
{-# NOINLINE [1] map #-}
map :: Box (a -> b) -> Events a -> Events b
map :: Box (a -> b) -> Events a -> Events b
map f :: Box (a -> b)
f (Just' x :: a
x ::: xs :: O (Events a)
xs) =  (b -> Maybe' b
forall a. a -> Maybe' a
Just' (Box (a -> b) -> a -> b
forall a. Box a -> a
unbox Box (a -> b)
f a
x)) Maybe' b -> O (Events b) -> Events b
forall a. a -> O (Str a) -> Str a
::: Events b -> O (Events b)
forall a. a -> O a
delay (Box (a -> b) -> Events a -> Events b
forall a b. Box (a -> b) -> Events a -> Events b
map Box (a -> b)
f (O (Events a) -> Events a
forall a. O a -> a
adv O (Events a)
xs))
map f :: Box (a -> b)
f (Nothing' ::: xs :: O (Events a)
xs) = Maybe' b
forall a. Maybe' a
Nothing' Maybe' b -> O (Events b) -> Events b
forall a. a -> O (Str a) -> Str a
::: Events b -> O (Events b)
forall a. a -> O a
delay (Box (a -> b) -> Events a -> Events b
forall a b. Box (a -> b) -> Events a -> Events b
map Box (a -> b)
f (O (Events a) -> Events a
forall a. O a -> a
adv O (Events a)
xs))

-- | An event that will never occur.
never :: Events a
never :: Events a
never = Maybe' a
forall a. Maybe' a
Nothing' Maybe' a -> O (Events a) -> Events a
forall a. a -> O (Str a) -> Str a
::: Events a -> O (Events a)
forall a. a -> O a
delay Events a
forall a. Events a
never

-- | @switch s e@ will behave like @s@ but switches to @s'$ every time
-- the event 'e' occurs with some value @s'@.
switch :: Str a -> Events (Str a) -> Str a
switch :: Str a -> Events (Str a) -> Str a
switch (x :: a
x ::: xs :: O (Str a)
xs) (Nothing' ::: fas :: O (Events (Str a))
fas) = a
x a -> O (Str a) -> Str a
forall a. a -> O (Str a) -> Str a
::: Str a -> O (Str a)
forall a. a -> O a
delay (Str a -> Events (Str a) -> Str a
forall a. Str a -> Events (Str a) -> Str a
switch (O (Str a) -> Str a
forall a. O a -> a
adv O (Str a)
xs)  (O (Events (Str a)) -> Events (Str a)
forall a. O a -> a
adv O (Events (Str a))
fas))
switch  _xs :: Str a
_xs       (Just' (a :: a
a ::: as :: O (Str a)
as) ::: fas :: O (Events (Str a))
fas)   = a
a a -> O (Str a) -> Str a
forall a. a -> O (Str a) -> Str a
::: ((Str a -> Events (Str a) -> Str a)
-> O (Str a -> Events (Str a) -> Str a)
forall a. a -> O a
delay Str a -> Events (Str a) -> Str a
forall a. Str a -> Events (Str a) -> Str a
switch O (Str a -> Events (Str a) -> Str a)
-> O (Str a) -> O (Events (Str a) -> Str a)
forall a b. O (a -> b) -> O a -> O b
<*> O (Str a)
as O (Events (Str a) -> Str a) -> O (Events (Str a)) -> O (Str a)
forall a b. O (a -> b) -> O a -> O b
<*> O (Events (Str a))
fas)


-- | Like 'switch' but works on stream functions instead of
-- streams. That is, @switchTrans s e@ will behave like @s@ but
-- switches to @s'$ every time the event 'e' occurs with some value
-- @s'@.
switchTrans :: (Str a -> Str b) -> Events (Str a -> Str b) -> (Str a -> Str b)
switchTrans :: (Str a -> Str b) -> Events (Str a -> Str b) -> Str a -> Str b
switchTrans f :: Str a -> Str b
f es :: Events (Str a -> Str b)
es as :: Str a
as = Str b -> Events (Str a -> Str b) -> Str a -> Str b
forall b a. Str b -> Events (Str a -> Str b) -> Str a -> Str b
switchTrans' (Str a -> Str b
f Str a
as) Events (Str a -> Str b)
es Str a
as

-- | Helper function for 'switchTrans'.
switchTrans' :: Str b -> Events (Str a -> Str b) -> Str a -> Str b
switchTrans' :: Str b -> Events (Str a -> Str b) -> Str a -> Str b
switchTrans' (b :: b
b ::: bs :: O (Str b)
bs) (Nothing' ::: fs :: O (Events (Str a -> Str b))
fs) (_:::as :: O (Str a)
as) = b
b b -> O (Str b) -> Str b
forall a. a -> O (Str a) -> Str a
::: ((Str b -> Events (Str a -> Str b) -> Str a -> Str b)
-> O (Str b -> Events (Str a -> Str b) -> Str a -> Str b)
forall a. a -> O a
delay Str b -> Events (Str a -> Str b) -> Str a -> Str b
forall b a. Str b -> Events (Str a -> Str b) -> Str a -> Str b
switchTrans' O (Str b -> Events (Str a -> Str b) -> Str a -> Str b)
-> O (Str b) -> O (Events (Str a -> Str b) -> Str a -> Str b)
forall a b. O (a -> b) -> O a -> O b
<*> O (Str b)
bs O (Events (Str a -> Str b) -> Str a -> Str b)
-> O (Events (Str a -> Str b)) -> O (Str a -> Str b)
forall a b. O (a -> b) -> O a -> O b
<*> O (Events (Str a -> Str b))
fs O (Str a -> Str b) -> O (Str a) -> O (Str b)
forall a b. O (a -> b) -> O a -> O b
<*> O (Str a)
as)
switchTrans' _xs :: Str b
_xs        (Just' f :: Str a -> Str b
f ::: fs :: O (Events (Str a -> Str b))
fs)  as :: Str a
as@(_:::as' :: O (Str a)
as') = b
b' b -> O (Str b) -> Str b
forall a. a -> O (Str a) -> Str a
::: ((Str b -> Events (Str a -> Str b) -> Str a -> Str b)
-> O (Str b -> Events (Str a -> Str b) -> Str a -> Str b)
forall a. a -> O a
delay Str b -> Events (Str a -> Str b) -> Str a -> Str b
forall b a. Str b -> Events (Str a -> Str b) -> Str a -> Str b
switchTrans' O (Str b -> Events (Str a -> Str b) -> Str a -> Str b)
-> O (Str b) -> O (Events (Str a -> Str b) -> Str a -> Str b)
forall a b. O (a -> b) -> O a -> O b
<*> O (Str b)
bs' O (Events (Str a -> Str b) -> Str a -> Str b)
-> O (Events (Str a -> Str b)) -> O (Str a -> Str b)
forall a b. O (a -> b) -> O a -> O b
<*> O (Events (Str a -> Str b))
fs O (Str a -> Str b) -> O (Str a) -> O (Str b)
forall a b. O (a -> b) -> O a -> O b
<*> O (Str a)
as')
  where (b' :: b
b' ::: bs' :: O (Str b)
bs') = Str a -> Str b
f Str a
as


-- | Trigger an event as every time the given predicate turns true on
-- the given stream. The value of the event is the same as that of the
-- stream at that time.
trigger :: Box (a -> Bool) -> Str a -> Events a
trigger :: Box (a -> Bool) -> Str a -> Events a
trigger p :: Box (a -> Bool)
p (x :: a
x ::: xs :: O (Str a)
xs) = Maybe' a
x' Maybe' a -> O (Events a) -> Events a
forall a. a -> O (Str a) -> Str a
::: ((Str a -> Events a) -> O (Str a -> Events a)
forall a. a -> O a
delay (Box (a -> Bool) -> Str a -> Events a
forall a. Box (a -> Bool) -> Str a -> Events a
trigger Box (a -> Bool)
p) O (Str a -> Events a) -> O (Str a) -> O (Events a)
forall a b. O (a -> b) -> O a -> O b
<*> O (Str a)
xs)
  where x' :: Maybe' a
x' = if Box (a -> Bool) -> a -> Bool
forall a. Box a -> a
unbox Box (a -> Bool)
p a
x then a -> Maybe' a
forall a. a -> Maybe' a
Just' a
x else Maybe' a
forall a. Maybe' a
Nothing'

-- | Trigger an event every time the given function produces a 'Just''
-- value.
triggerMap :: Box (a -> Maybe' b) -> Str a -> Events b
triggerMap :: Box (a -> Maybe' b) -> Str a -> Events b
triggerMap = Box (a -> Maybe' b) -> Str a -> Events b
forall a b. Box (a -> b) -> Str a -> Str b
S.map



{-# RULES

  "map/map" forall f g xs.
    map f (map g xs) = map (box (unbox f . unbox g)) xs ;

#-}