{-# LANGUAGE Arrows #-}
-- |
-- Copyright  : (c) Ivan Perez, 2019-2022
--              (c) Ivan Perez and Manuel Baerenz, 2016-2018
-- License    : BSD3
-- Maintainer : ivan.perez@keera.co.uk
--
-- Discrete to continuous-time signal functions.
module FRP.BearRiver.Hybrid where

-- External imports
import Control.Arrow (arr, returnA, (<<<))

-- Internal imports (dunai)
import Data.MonadicStreamFunction (accumulateWith, feedback)

-- Internal imports (bearriver)
import FRP.BearRiver.Arrow        (dup)
import FRP.BearRiver.Event        (Event (..), event)
import FRP.BearRiver.InternalCore (SF)

-- * Discrete to continuous-time signal functions

-- ** Wave-form generation

-- | Zero-order hold.
--
-- Converts a discrete-time signal into a continuous-time signal, by holding
-- the last value until it changes in the input signal. The given parameter may
-- be used for time zero, and until the first event occurs in the input signal,
-- so hold is always well-initialized.
--
-- >>> embed (hold 1) (deltaEncode 0.1 [NoEvent, NoEvent, Event 2, NoEvent, Event 3, NoEvent])
-- [1,1,2,2,3,3]
hold :: Monad m => a -> SF m (Event a) a
hold :: forall (m :: * -> *) a. Monad m => a -> SF m (Event a) a
hold a
a = a
-> MSF (ClockInfo m) (Event a, a) (a, a)
-> MSF (ClockInfo m) (Event a) a
forall (m :: * -> *) c a b.
Monad m =>
c -> MSF m (a, c) (b, c) -> MSF m a b
feedback a
a (MSF (ClockInfo m) (Event a, a) (a, a)
 -> MSF (ClockInfo m) (Event a) a)
-> MSF (ClockInfo m) (Event a, a) (a, a)
-> MSF (ClockInfo m) (Event a) a
forall a b. (a -> b) -> a -> b
$ ((Event a, a) -> (a, a)) -> MSF (ClockInfo m) (Event a, a) (a, a)
forall b c. (b -> c) -> MSF (ClockInfo m) b c
forall (a :: * -> * -> *) b c. Arrow a => (b -> c) -> a b c
arr (((Event a, a) -> (a, a)) -> MSF (ClockInfo m) (Event a, a) (a, a))
-> ((Event a, a) -> (a, a))
-> MSF (ClockInfo m) (Event a, a) (a, a)
forall a b. (a -> b) -> a -> b
$ \(Event a
e, a
a') ->
  a -> (a, a)
forall a. a -> (a, a)
dup (a -> (a -> a) -> Event a -> a
forall a b. a -> (b -> a) -> Event b -> a
event a
a' a -> a
forall a. a -> a
id Event a
e)

-- ** Accumulators

-- | Accumulator parameterized by the accumulation function.
accumBy :: Monad m => (b -> a -> b) -> b -> SF m (Event a) (Event b)
accumBy :: forall (m :: * -> *) b a.
Monad m =>
(b -> a -> b) -> b -> SF m (Event a) (Event b)
accumBy b -> a -> b
f b
b = SF m a b -> SF m (Event a) (Event b)
forall (m :: * -> *) a b.
Monad m =>
SF m a b -> SF m (Event a) (Event b)
mapEventS (SF m a b -> SF m (Event a) (Event b))
-> SF m a b -> SF m (Event a) (Event b)
forall a b. (a -> b) -> a -> b
$ (a -> b -> b) -> b -> SF m a b
forall (m :: * -> *) a s.
Monad m =>
(a -> s -> s) -> s -> MSF m a s
accumulateWith ((b -> a -> b) -> a -> b -> b
forall a b c. (a -> b -> c) -> b -> a -> c
flip b -> a -> b
f) b
b

-- | Zero-order hold accumulator parameterized by the accumulation function.
accumHoldBy :: Monad m => (b -> a -> b) -> b -> SF m (Event a) b
accumHoldBy :: forall (m :: * -> *) b a.
Monad m =>
(b -> a -> b) -> b -> SF m (Event a) b
accumHoldBy b -> a -> b
f b
b = b
-> MSF (ClockInfo m) (Event a, b) (b, b)
-> MSF (ClockInfo m) (Event a) b
forall (m :: * -> *) c a b.
Monad m =>
c -> MSF m (a, c) (b, c) -> MSF m a b
feedback b
b (MSF (ClockInfo m) (Event a, b) (b, b)
 -> MSF (ClockInfo m) (Event a) b)
-> MSF (ClockInfo m) (Event a, b) (b, b)
-> MSF (ClockInfo m) (Event a) b
forall a b. (a -> b) -> a -> b
$ ((Event a, b) -> (b, b)) -> MSF (ClockInfo m) (Event a, b) (b, b)
forall b c. (b -> c) -> MSF (ClockInfo m) b c
forall (a :: * -> * -> *) b c. Arrow a => (b -> c) -> a b c
arr (((Event a, b) -> (b, b)) -> MSF (ClockInfo m) (Event a, b) (b, b))
-> ((Event a, b) -> (b, b))
-> MSF (ClockInfo m) (Event a, b) (b, b)
forall a b. (a -> b) -> a -> b
$ \(Event a
a, b
b') ->
  let b'' :: b
b'' = b -> (a -> b) -> Event a -> b
forall a b. a -> (b -> a) -> Event b -> a
event b
b' (b -> a -> b
f b
b') Event a
a
  in (b
b'', b
b'')

-- * Events

-- | Apply an 'SF' to every input. Freezes temporarily if the input is
-- 'NoEvent', and continues as soon as an 'Event' is received.
mapEventS :: Monad m => SF m a b -> SF m (Event a) (Event b)
mapEventS :: forall (m :: * -> *) a b.
Monad m =>
SF m a b -> SF m (Event a) (Event b)
mapEventS SF m a b
msf = proc Event a
eventA -> case Event a
eventA of
  Event a
a -> (b -> Event b) -> MSF (ClockInfo m) b (Event b)
forall b c. (b -> c) -> MSF (ClockInfo m) b c
forall (a :: * -> * -> *) b c. Arrow a => (b -> c) -> a b c
arr b -> Event b
forall a. a -> Event a
Event MSF (ClockInfo m) b (Event b)
-> SF m a b -> MSF (ClockInfo m) a (Event b)
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
<<< SF m a b
msf -< a
a
  Event a
NoEvent -> MSF (ClockInfo m) (Event b) (Event b)
forall (a :: * -> * -> *) b. Arrow a => a b b
returnA           -< Event b
forall a. Event a
NoEvent