content: -- |
  -- Module      : FRP.BearRiver.Basic
  -- Copyright   : (c) Ivan Perez, 2014-2022
  --               (c) George Giorgidze, 2007-2012
  --               (c) Henrik Nilsson, 2005-2006
  --               (c) Antony Courtney and Henrik Nilsson, Yale University, 2003-2004
  -- License     : BSD-style (see the LICENSE file in the distribution)
  --
  -- Maintainer  : ivan.perez@keera.co.uk
  -- Stability   : provisional
  -- Portability : non-portable (GHC extensions)
  --
  -- Defines basic signal functions, and elementary ways of altering them.
  --
  -- This module defines very basic ways of creating and modifying signal
  -- functions. In particular, it defines ways of creating constant output
  -- producing SFs, and SFs that just pass the signal through unmodified.
  --
  -- It also defines ways of altering the input and the output signal only by
  -- inserting one value in the signal, or by transforming it.
  module FRP.BearRiver.Basic
      (
        -- * Basic signal functions
        identity
      , constant
  
        -- ** Initialization
      , (-->)
      , (-:>)
      , (>--)
      , (-=>)
      , (>=-)
      , initially
      )
    where
  
  -- External imports
  import qualified Control.Category as Category
  
  -- Internal imports (dunai)
  import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF))
  
  -- Internal imports
  import FRP.BearRiver.InternalCore (SF, arr)
  
  infixr 0 -->, -:>, >--, -=>, >=-
  
  -- * Basic signal functions
  
  -- | Identity: identity = arr id
  --
  -- Using 'identity' is preferred over lifting id, since the arrow combinators
  -- know how to optimise certain networks based on the transformations being
  -- applied.
  identity :: Monad m => SF m a a
  identity = Category.id
  
  -- | Identity: constant b = arr (const b)
  --
  -- Using 'constant' is preferred over lifting const, since the arrow combinators
  -- know how to optimise certain networks based on the transformations being
  -- applied.
  constant :: Monad m => b -> SF m a b
  constant = arr . const
  
  -- * Initialization
  
  -- | Initialization operator (cf. Lustre/Lucid Synchrone).
  --
  -- The output at time zero is the first argument, and from that point on it
  -- behaves like the signal function passed as second argument.
  (-->) :: Monad m => b -> SF m a b -> SF m a b
  b0 --> sf = MSF $ \a -> do
    (_b, sf') <- unMSF sf a
    return (b0, sf')
  
  -- | Output pre-insert operator.
  --
  -- Insert a sample in the output, and from that point on, behave like the given
  -- sf.
  (-:>) :: Monad m => b -> SF m a b -> SF m a b
  b -:> sf = MSF $ \_a -> return (b, sf)
  
  -- | Input initialization operator.
  --
  -- The input at time zero is the first argument, and from that point on it
  -- behaves like the signal function passed as second argument.
  (>--) :: Monad m => a -> SF m a b -> SF m a b
  a0 >-- sf = MSF $ \_ -> unMSF sf a0
  
  -- | Transform initial output value.
  --
  -- Applies a transformation 'f' only to the first output value at time zero.
  (-=>) :: Monad m => (b -> b) -> SF m a b -> SF m a b
  f -=> sf = MSF $ \a -> do
    (b, sf') <- unMSF sf a
    return (f b, sf')
  
  -- | Transform initial input value.
  --
  -- Applies a transformation 'f' only to the first input value at time zero.
  (>=-) :: Monad m => (a -> a) -> SF m a b -> SF m a b
  f >=- sf = MSF $ \a -> do
    (b, sf') <- unMSF sf (f a)
    return (b, sf')
  
  -- | Override initial value of input signal.
  initially :: Monad m => a -> SF m a a
  initially = (--> identity)
  