-- {-# LANGUAGE #-}
-- DatatypeContexts: misfeature
-- lowlevel interface of Sys
module SSM (SSM(..), ssmSer, ssmPar, ssmPure,
) where
{-
The Sys data type abstracts systems (sequence operators) governed by
update equations and initial conditons.
Causality refers to the principle that the operator cannot use
"future" sequence data.
The code is split in two parts: low-level composition operations and
abstrac data type + class instances.
1. Primitives & compositions
----------------------------
Composing Sys is like composing functions, placing them in
series linking the output of one to input of another. The state
inputs/outputs of both Sys are bundled in parallel.
Note that state is *private*. It is not threaded between both
elements that are composed, i.e. this is not a State Monad.
-}
-- NOTE: The arrow instance relies on the fact that at least the I/O
-- tupling are (,) so using a different class for Cons is probably not
-- a good idea.
-- Implement update composition (ud) and state product (sp)
-- separately, then combine in SSM data ops.
udSer :: Monad m =>
((s1, b) -> m (s1, c)) ->
((s2, a) -> m (s2, b)) ->
((s1,s2), a) -> m ((s1,s2), c)
udSer f g = fg where
fg ((s1,s2), a) = do
(s2', b) <- g (s2, a)
(s1', c) <- f (s1, b)
return ((s1',s2'), c)
{-
Another way to compose operators is to take their product, placing
them in parallel.
-}
udPar :: Monad m =>
((s1, a) -> m (s1, c)) ->
((s2, b) -> m (s2, d)) ->
((s1,s2), (a,b)) -> m ((s1,s2), (c,d))
udPar f g = fg where
fg ((s1,s2), (a,b)) = do
(s1',c) <- f (s1, a)
(s2',d) <- g (s2, b)
return ((s1',s2'), (c,d))
{-
Lifting pure functions. A pure function is an Sys with void
state.
-}
udPure :: Monad m => (a -> b) -> ((), a) -> m ((), b)
udPure f ((), a) = return ((), f a)
-- State product operations are represented in terms of these two
-- functions. To keep things simple we just use binary tuples hidden
-- in the monad.
sp :: Monad m => m a -> m b -> m (a, b)
ma `sp` mb = do
a <- ma
b <- mb
return $ (a,b)
-- Data structure wrapping. Like Sys, but no data hiding.
data SSM m s i o = SSM ((s, i) -> m (s, o)) (m s)
-- Some generalized Arrow behaviour (SSM includes extra "growing" state parameter).
ssmSer (SSM f f0) (SSM g g0) = SSM (f `udSer` g) (f0 `sp` g0)
ssmPar (SSM f f0) (SSM g g0) = SSM (f `udPar` g) (f0 `sp` g0)
ssmPure f = SSM (udPure f) (return ())