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

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


module Rattus.Event
  ( map
  , never
  , switch
  , switchTrans
  , dswitchTrans
  , combine
  , Event
  , trigger
  , triggerMap
  )

where

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

import Prelude hiding (map,zipWith)

-- | Events are simply streams of 'Maybe''s.
type Event 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) -> Event a -> Event b
map :: forall a b. Box (a -> b) -> Event a -> Event b
map Box (a -> b)
f (Just' a
x ::: O (Str (Maybe' a))
xs) =  (forall a. a -> Maybe' a
Just' (forall a. Box a -> a
unbox Box (a -> b)
f a
x)) forall a. a -> O (Str a) -> Str a
::: forall a. a -> O a
delay (forall a b. Box (a -> b) -> Event a -> Event b
map Box (a -> b)
f (forall a. O a -> a
adv O (Str (Maybe' a))
xs))
map Box (a -> b)
f (Maybe' a
Nothing' ::: O (Str (Maybe' a))
xs) = forall a. Maybe' a
Nothing' forall a. a -> O (Str a) -> Str a
::: forall a. a -> O a
delay (forall a b. Box (a -> b) -> Event a -> Event b
map Box (a -> b)
f (forall a. O a -> a
adv O (Str (Maybe' a))
xs))

-- | An event that will never occur.
never :: Event a
never :: forall a. Event a
never = forall a. Maybe' a
Nothing' forall a. a -> O (Str a) -> Str a
::: forall a. a -> O a
delay forall a. Event 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 -> Event (Str a) -> Str a
switch :: forall a. Str a -> Event (Str a) -> Str a
switch (a
x ::: O (Str a)
xs) (Maybe' (Str a)
Nothing' ::: O (Str (Maybe' (Str a)))
fas) = a
x forall a. a -> O (Str a) -> Str a
::: forall a. a -> O a
delay (forall a. Str a -> Event (Str a) -> Str a
switch (forall a. O a -> a
adv O (Str a)
xs)  (forall a. O a -> a
adv O (Str (Maybe' (Str a)))
fas))
switch  Str a
_xs       (Just' (a
a ::: O (Str a)
as) ::: O (Str (Maybe' (Str a)))
fas)   = a
a forall a. a -> O (Str a) -> Str a
::: (forall a. a -> O a
delay forall a. Str a -> Event (Str a) -> Str a
switch forall a b. O (a -> b) -> O a -> O b
<#> O (Str a)
as forall a b. O (a -> b) -> O a -> O b
<#> O (Str (Maybe' (Str a)))
fas)


-- | @combine f s e@ is similar to @switch s e@, but instead of
-- switching to new streams @s'@ every time the event 'e' occurs with
-- some value @s'@, the new stream @s'@ is combined with the current
-- stream @s@ using @zipWith f s' s@.
combine :: Box (a -> a -> a) -> Str a -> Event (Str a) -> Str a
combine :: forall a. Box (a -> a -> a) -> Str a -> Event (Str a) -> Str a
combine Box (a -> a -> a)
f (a
x ::: O (Str a)
xs) (Maybe' (Str a)
Nothing' ::: O (Str (Maybe' (Str a)))
fas) = a
x  forall a. a -> O (Str a) -> Str a
::: forall a. a -> O a
delay (forall a. Box (a -> a -> a) -> Str a -> Event (Str a) -> Str a
combine Box (a -> a -> a)
f (forall a. O a -> a
adv O (Str a)
xs) (forall a. O a -> a
adv O (Str (Maybe' (Str a)))
fas))
combine Box (a -> a -> a)
f Str a
xs         (Just' Str a
as ::: O (Str (Maybe' (Str a)))
fas) = a
x' forall a. a -> O (Str a) -> Str a
::: forall a. a -> O a
delay (forall a. Box (a -> a -> a) -> Str a -> Event (Str a) -> Str a
combine Box (a -> a -> a)
f (forall a. O a -> a
adv O (Str a)
xs') (forall a. O a -> a
adv O (Str (Maybe' (Str a)))
fas))
  where (a
x' ::: O (Str a)
xs') = forall a b c. Box (a -> b -> c) -> Str a -> Str b -> Str c
zipWith Box (a -> a -> a)
f Str a
xs Str a
as


-- | 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) -> Event (Str a -> Str b) -> (Str a -> Str b)
switchTrans :: forall a b.
(Str a -> Str b) -> Event (Str a -> Str b) -> Str a -> Str b
switchTrans Str a -> Str b
f Event (Str a -> Str b)
es Str a
as = forall b a. Str b -> Event (Str a -> Str b) -> Str a -> Str b
switchTrans' (Str a -> Str b
f Str a
as) Event (Str a -> Str b)
es Str a
as

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



-- | Like 'switchTrans' but takes a delayed event as input, which
-- allows the switch to incorporate feedback from itself.
dswitchTrans :: (Str a -> Str b) -> O (Event (Str a -> Str b)) -> (Str a -> Str b)
dswitchTrans :: forall a b.
(Str a -> Str b) -> O (Event (Str a -> Str b)) -> Str a -> Str b
dswitchTrans Str a -> Str b
f O (Event (Str a -> Str b))
es Str a
as = forall b a. Str b -> O (Event (Str a -> Str b)) -> Str a -> Str b
dswitchTrans' (Str a -> Str b
f Str a
as) O (Event (Str a -> Str b))
es Str a
as

-- | Helper function for 'dswitchTrans'.
dswitchTrans' :: Str b -> O (Event (Str a -> Str b)) -> Str a -> Str b
dswitchTrans' :: forall b a. Str b -> O (Event (Str a -> Str b)) -> Str a -> Str b
dswitchTrans' (b
b ::: O (Str b)
bs) O (Event (Str a -> Str b))
de (a
_:::O (Str a)
as) = b
b forall a. a -> O (Str a) -> Str a
::: (forall a. a -> O a
delay forall b a. Str b -> Event (Str a -> Str b) -> Str a -> Str b
switchTrans' forall a b. O (a -> b) -> O a -> O b
<#> O (Str b)
bs forall a b. O (a -> b) -> O a -> O b
<#> O (Event (Str a -> Str b))
de forall a b. O (a -> b) -> O a -> O b
<#> O (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 -> Event a
trigger :: forall a. Box (a -> Bool) -> Str a -> Event a
trigger Box (a -> Bool)
p (a
x ::: O (Str a)
xs) = Maybe' a
x' forall a. a -> O (Str a) -> Str a
::: (forall a. a -> O a
delay (forall a. Box (a -> Bool) -> Str a -> Event a
trigger Box (a -> Bool)
p) forall a b. O (a -> b) -> O a -> O b
<#> O (Str a)
xs)
  where x' :: Maybe' a
x' = if forall a. Box a -> a
unbox Box (a -> Bool)
p a
x then forall a. a -> Maybe' a
Just' a
x else forall a. Maybe' a
Nothing'

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


{-# RULES

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

#-}