{-# OPTIONS -fglasgow-exts #-} {- | Processes that use only the current and past data. Essentially this is a data type for the 'Synthesizer.State.Signal.crochetL' function. -} module Synthesizer.Causal.Process ( T, fromStateMaybe, fromState, fromSimpleModifier, map, first, second, compose, split, fanout, loop, {- We don't re-export these identifiers because people could abuse them for other Arrows. (>>>), (***), (&&&), (Arrow.^<<), (Arrow.^>>), (Arrow.<<^), (Arrow.>>^), -} apply, applyFst, applySnd, apply2, feed, crochetL, scanL, zipWith, ) where import qualified Synthesizer.State.Signal as Sig import qualified Synthesizer.Plain.Modifier as Modifier -- import qualified Control.Arrow as Arrow import Control.Arrow (Arrow(..), {- ArrowApply(..), -} ArrowLoop(..), Kleisli(Kleisli), runKleisli, ) import Control.Monad.State (State(State), runState, StateT(StateT), runStateT, liftM, ) import Synthesizer.Utility (mapSnd) import Prelude hiding (map, zipWith, ) -- TODO: include ST monad for mutable arrays -- | Cf. StreamFusion 'Synthesizer.State.Signal.T' data T a b = forall s. -- Seq s => Cons !(a -> StateT s Maybe b) -- compute next value !s -- initial state {-# INLINE fromStateMaybe #-} fromStateMaybe :: (a -> StateT s Maybe b) -> s -> T a b fromStateMaybe = Cons {-# INLINE fromState #-} fromState :: (a -> State s b) -> s -> T a b fromState f s0 = fromStateMaybe (\x -> StateT (Just . runState (f x))) s0 {-# INLINE fromSimpleModifier #-} fromSimpleModifier :: Modifier.Simple s ctrl a b -> T (ctrl,a) b fromSimpleModifier (Modifier.Simple s f) = fromState (uncurry f) s {- It's almost a Kleisli Arrow, but the hidden type of the state disturbs. -} instance Arrow T where {-# INLINE pure #-} {-# INLINE (>>>) #-} {-# INLINE first #-} {-# INLINE second #-} {-# INLINE (***) #-} {-# INLINE (&&&) #-} pure = map (>>>) = compose first = liftKleisli first second = liftKleisli second (***) = split (&&&) = fanout {- I think we cannot define an ArrowApply instance, because we must extract the initial state somehow from the inner (T a b) which is not possible. instance ArrowApply T where -- app = Cons (runKleisli undefined) () app = first (arr (flip Cons () . runKleisli)) >>> app -} instance ArrowLoop T where {-# INLINE loop #-} loop = liftKleisli loop {-# INLINE extendStateFstT #-} extendStateFstT :: Monad m => StateT s m a -> StateT (t,s) m a extendStateFstT st = StateT (\(t0,s0) -> liftM (mapSnd (\s1 -> (t0,s1))) (runStateT st s0)) {-# INLINE extendStateSndT #-} extendStateSndT :: Monad m => StateT s m a -> StateT (s,t) m a extendStateSndT st = StateT (\(s0,t0) -> liftM (mapSnd (\s1 -> (s1,t0))) (runStateT st s0)) {-# INLINE liftKleisli #-} liftKleisli :: (forall s. Kleisli (StateT s Maybe) a0 a1 -> Kleisli (StateT s Maybe) b0 b1) -> T a0 a1 -> T b0 b1 liftKleisli op (Cons f s) = Cons (runKleisli $ op $ Kleisli f) s {-# INLINE liftKleisli2 #-} liftKleisli2 :: (forall s. Kleisli (StateT s Maybe) a0 a1 -> Kleisli (StateT s Maybe) b0 b1 -> Kleisli (StateT s Maybe) c0 c1) -> T a0 a1 -> T b0 b1 -> T c0 c1 liftKleisli2 op (Cons f s) (Cons g t) = Cons (runKleisli (Kleisli (extendStateSndT . f) `op` Kleisli (extendStateFstT . g))) (s,t) {-# INLINE map #-} map :: (a -> b) -> T a b map f = fromState (return . f) () {-# INLINE compose #-} compose :: T a b -> T b c -> T a c compose = liftKleisli2 (>>>) {-# INLINE split #-} split :: T a b -> T c d -> T (a,c) (b,d) split = liftKleisli2 (***) {-# INLINE fanout #-} fanout :: T a b -> T a c -> T a (b,c) fanout = liftKleisli2 (&&&) {-# INLINE apply #-} apply :: T a b -> Sig.T a -> Sig.T b apply (Cons f s) = Sig.crochetL (runStateT . f) s {-# INLINE applyFst #-} applyFst :: T (a,b) c -> Sig.T a -> T b c applyFst (Cons f s) x = Cons (\b -> do a <- extendStateFstT $ StateT $ Sig.viewL extendStateSndT (f (a,b))) (s,x) {-# INLINE applySnd #-} applySnd :: T (a,b) c -> Sig.T b -> T a c applySnd (Cons f s) x = Cons (\b -> do a <- extendStateFstT $ StateT $ Sig.viewL extendStateSndT (f (b,a))) (s,x) {-# INLINE apply2 #-} apply2 :: T (a,b) c -> Sig.T a -> Sig.T b -> Sig.T c apply2 f x y = apply (applyFst f x) y {-# INLINE feed #-} feed :: Sig.T a -> T () a feed = fromStateMaybe (const (StateT Sig.viewL)) {-# INLINE crochetL #-} crochetL :: (x -> acc -> Maybe (y, acc)) -> acc -> T x y crochetL f s = fromStateMaybe (StateT . f) s {-# INLINE scanL #-} scanL :: (acc -> x -> acc) -> acc -> T x acc scanL f start = fromState (\x -> State $ \acc -> (acc, f acc x)) start {-# INLINE zipWith #-} zipWith :: (a -> b -> c) -> Sig.T a -> T b c zipWith f = applyFst (map (uncurry f))