packages feed

dunai 0.2.0.0 → 0.3.0.0

raw patch · 21 files changed

+585/−250 lines, 21 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Control.Monad.Trans.MSF.GenLift: type Id a = a
- Control.Monad.Trans.MSF.GenLift: type Unwrapper m1 m2 t1 t2 = forall a b. (a -> m1 (t2 b)) -> (t1 a -> m2 b)
- Control.Monad.Trans.MSF.GenLift: type Wrapper m1 m2 t1 t2 = forall a b. (t1 a -> m2 b) -> (a -> m1 (t2 b))
- Control.Monad.Trans.MSF.Reader: type ReaderUnwrapper s m = Unwrapper (ReaderT s m) m ((,) s) Id
- Control.Monad.Trans.MSF.Reader: type ReaderWrapper s m = Wrapper (ReaderT s m) m ((,) s) Id
- Control.Monad.Trans.MSF.Reader: unwrapReaderT :: (a -> ReaderT s m b) -> (s, a) -> m b
- Control.Monad.Trans.MSF.Reader: wrapReaderT :: ((s, a) -> m b) -> a -> ReaderT s m b
- Control.Monad.Trans.MSF.Writer: unwrapMSFWriterT :: (Monad m, Functor m) => (a -> WriterT s m (b, ct)) -> a -> m ((s, b), ct)
- Control.Monad.Trans.MSF.Writer: wrapMSFWriterT :: (Monoid s, Monad m) => (a -> m ((s, b), ct)) -> a -> WriterT s m (b, ct)
- Control.Monad.Trans.MSF.Except: maybeToExceptS :: Monad m => MSF (MaybeT m) a b -> MSF (ExceptT () m) a b
+ Control.Monad.Trans.MSF.Except: maybeToExceptS :: (Functor m, Monad m) => MSF (MaybeT m) a b -> MSF (ExceptT () m) a b
- Data.VectorSpace: class Num (Groundring v) => RModule v where type Groundring v (^*) = flip (*^) (*^) = flip (^*) negateVector v = (- 1) *^ v v1 ^-^ v2 = v1 ^+^ negateVector v2 where {
+ Data.VectorSpace: class Num (Groundring v) => RModule v where type Groundring v (*^) = flip (^*) (^*) = flip (*^) negateVector v = (- 1) *^ v v1 ^-^ v2 = v1 ^+^ negateVector v2 where {

Files

dunai.cabal view
@@ -1,8 +1,9 @@ name:                dunai-version:             0.2.0.0+version:             0.3.0.0 synopsis:            Generalised reactive framework supporting classic, arrowized and monadic FRP.+homepage:            https://github.com/ivanperez-keera/dunai description:-  Dunai is DSL for strongly-typed CPS-based composable transformations.+  Dunai is a DSL for strongly-typed CPS-based composable transformations.   .   Dunai is based on a concept of Monadic Stream Functions (MSFs). MSFs are   transformations defined by a function @unMSF :: MSF m a b -> a -> m (b, MSF m a b)@@@ -42,11 +43,13 @@  -- You can disable the hlint test suite with -f-test-hlint flag test-hlint+  description: Enable hlint test suite   default: False   manual: True  -- You can disable the haddock coverage test suite with -f-test-doc-coverage flag test-doc-coverage+  description: Enable haddock coverage test suite   default: False   manual: True 
src/Control/Arrow/Util.hs view
@@ -1,18 +1,20 @@+-- | Utility functions to work with 'Arrow's. module Control.Arrow.Util where  import Control.Arrow --- Hah! I shall implement this for TimelessSFs and SFs at the same time!+-- | Constantly produce the same output. constantly :: Arrow a => b -> a c b constantly = arr . const {-# INLINE constantly #-} --- More strongly bound arrow combinators+-- | Alternative implementation of '<<<' that binds more strongly. infixr 4 <-< (<-<) :: Arrow a => a c d -> a b c -> a b d (<-<) = (<<<) {-# INLINE (<-<) #-} +-- | Alternative implementation of '>>>' that binds more strongly. infixr 4 >-> (>->) :: Arrow a => a b c -> a c d -> a b d (>->) = (>>>)@@ -27,9 +29,12 @@ -- sink :: Arrow a => a b c -> a c () -> a b c -- a1 `sink` a2 = a1 >>> (id &&& a2) >>> arr fst --- Apply functions at the end+-- * Apply functions at the end.+--+-- | Alternative name for '^<<'. elementwise :: Arrow a => (c -> d) -> a b c -> a b d elementwise = (^<<) +-- | Apply a curried function with two arguments to the outputs of two arrows. elementwise2 :: Arrow a => (c -> d -> e) -> a b c -> a b d -> a b e elementwise2 op a1 a2 = (a1 &&& a2) >>^ uncurry op
src/Control/Monad/Trans/MSF.hs view
@@ -1,5 +1,7 @@ {-# LANGUAGE Rank2Types #-} +-- | This module reexports nearly all submodules. RWS is not exported since+-- names collide with Reader, State and Writer. module Control.Monad.Trans.MSF     ( module Control.Monad.Trans.MSF.GenLift     , module Control.Monad.Trans.MSF.Except@@ -9,9 +11,6 @@     , module Control.Monad.Trans.MSF.Writer     )   where---- Caution: RWS is not exported since names collide with Reader, State and--- Writer  import Control.Monad.Trans.MSF.GenLift import Control.Monad.Trans.MSF.Except
src/Control/Monad/Trans/MSF/Except.hs view
@@ -1,17 +1,23 @@ {-# LANGUAGE Arrows              #-} {-# LANGUAGE Rank2Types          #-}+-- | 'MSF's in the 'ExceptT' monad are monadic stream functions+--   that can throw exceptions,+--   i.e. return an exception value instead of a continuation.+--   This module gives ways to throw exceptions in various ways,+--   and to handle them through a monadic interface. module Control.Monad.Trans.MSF.Except   ( module Control.Monad.Trans.MSF.Except   , module Control.Monad.Trans.Except   ) where  -- External+ import           Control.Applicative import qualified Control.Category           as Category import           Control.Monad              (liftM, ap) import           Control.Monad.Trans.Class import           Control.Monad.Trans.Except hiding (liftCallCC, liftListen, liftPass) -- Avoid conflicting exports-import Control.Monad.Trans.Maybe+import           Control.Monad.Trans.Maybe  -- Internal -- import Control.Monad.Trans.MSF.GenLift@@ -19,70 +25,77 @@  -- * Throwing exceptions +-- | Throw the exception 'e' whenever the function evaluates to 'True'. throwOnCond :: Monad m => (a -> Bool) -> e -> MSF (ExceptT e m) a a throwOnCond cond e = proc a -> if cond a-    then arrM throwE -< e-    else returnA -< a+  then throwS  -< e+  else returnA -< a +-- | Variant of 'throwOnCond' for Kleisli arrows.+-- | Throws the exception when the input is 'True'. throwOnCondM :: Monad m => (a -> m Bool) -> e -> MSF (ExceptT e m) a a throwOnCondM cond e = proc a -> do-    b <- arrM (lift . cond) -< a-    if b-      then arrM throwE -< e-      else returnA -< a+  b <- arrM (lift . cond) -< a+  if b+    then throwS  -< e+    else returnA -< a +-- | Throw the exception when the input is 'True'. throwOn :: Monad m => e -> MSF (ExceptT e m) Bool () throwOn e = proc b -> throwOn' -< (b, e) +-- | Variant of 'throwOn', where the exception may change every tick. throwOn' :: Monad m => MSF (ExceptT e m) (Bool, e) () throwOn' = proc (b, e) -> if b-    then arrM throwE -< e-    else returnA -< ()+  then throwS  -< e+  else returnA -< () +-- | When the input is 'Just e', throw the exception 'e'.+--   (Does not output any actual data.) throwMaybe :: Monad m => MSF (ExceptT e m) (Maybe e) (Maybe a)-throwMaybe = mapMaybeS $ arrM throwE+throwMaybe = mapMaybeS throwS +-- | Immediately throw the incoming exception. throwS :: Monad m => MSF (ExceptT e m) e a throwS = arrM throwE +-- | Immediately throw the given exception. throw :: Monad m => e -> MSF (ExceptT e m) a b throw = arrM_ . throwE +-- | Do not throw an exception. pass :: Monad m => MSF (ExceptT e m) a a pass = Category.id  -- | Whenever 'Nothing' is thrown, throw '()' instead.-maybeToExceptS :: Monad m => MSF (MaybeT m) a b -> MSF (ExceptT () m) a b+maybeToExceptS :: (Functor m, Monad m) => MSF (MaybeT m) a b -> MSF (ExceptT () m) a b maybeToExceptS = liftMSFPurer (ExceptT . (maybe (Left ()) Right <$>) . runMaybeT)  -- * Catching exceptions -{--catchS' :: Monad m => MSF (ExceptT e m) a b -> (e -> m (b, MSF m a b)) -> MSF m a b-catchS' msf f = MSF $ \a -> (unMSF msf a) f `catchFinal` f--}+-- | Catch an exception in an 'MSF'. As soon as an exception occurs,+--   the current continuation is replaced by a new 'MSF', the exception handler,+--   based on the exception value.+--   For exception catching where the handler can throw further exceptions,+--   see 'MSFExcept' further below. catchS :: Monad m => MSF (ExceptT e m) a b -> (e -> MSF m a b) -> MSF m a b catchS msf f = MSF $ \a -> do-    cont <- runExceptT $ unMSF msf a-    case cont of-        Left e          -> unMSF (f e) a-        Right (b, msf') -> return (b, msf' `catchS` f)---- catchFinal :: Monad m => ExceptT e m a -> (e -> m a) -> m a--- catchFinal action f = do---     ea <- runExceptT action---     case ea of---         Left  e -> f e---         Right a -> return a+  cont <- runExceptT $ unMSF msf a+  case cont of+    Left e          -> unMSF (f e) a+    Right (b, msf') -> return (b, msf' `catchS` f) --- Similar to delayed switching. Looses a b in case of exception+-- | Similar to Yampa's delayed switching. Looses a 'b' in case of an exception. untilE :: Monad m => MSF m a b -> MSF m b (Maybe e)        -> MSF (ExceptT e m) a b untilE msf msfe = proc a -> do-    b <- liftMSFTrans msf -< a-    me <- liftMSFTrans msfe -< b-    inExceptT -< (ExceptT . return) (maybe (Right b) Left me)+  b  <- liftMSFTrans msf  -< a+  me <- liftMSFTrans msfe -< b+  inExceptT -< ExceptT $ return $ maybe (Right b) Left me +-- | Escape an 'ExceptT' layer by outputting the exception whenever it occurs.+--   If an exception occurs, the current 'MSF' continuation is tested again+--   on the next input. exceptS :: Monad m => MSF (ExceptT e m) a b -> MSF m a (Either e b) exceptS msf = go  where@@ -92,22 +105,38 @@             Left e          -> return (Left e,  go)             Right (b, msf') -> return (Right b, exceptS msf') +-- | Embed an 'ExceptT' value inside the 'MSF'.+--   Whenever the input value is an ordinary value,+--   it is passed on. If it is an exception, it is raised. inExceptT :: Monad m => MSF (ExceptT e m) (ExceptT e m a) a-inExceptT = arrM id -- extracts value from monadic action+inExceptT = arrM id -{--tagged :: MSF (ExceptT e m) a b -> MSF (ExceptT t m) (a, t) b-tagged msf = MSF $ \(a, t) -> ExceptT $ do+-- | In case an exception occurs in the first argument,+--   replace the exception by the second component of the tuple.+tagged :: Monad m => MSF (ExceptT e1 m) a b -> MSF (ExceptT e2 m) (a, e2) b+tagged msf = MSF $ \(a, e2) -> ExceptT $ do   cont <- runExceptT $ unMSF msf a   case cont of-    Left  e     -> _ return t-    Right bmsf' -> _ return bmsf'-    -}+    Left e1 -> return $ Left e2+    Right (b, msf') -> return $ Right (b, tagged msf') + -- * Monad interface for Exception MSFs +-- | 'MSF's with an 'ExceptT' transformer layer+--   are in fact monads /in the exception type/.+--+--   * 'return' corresponds to throwing an exception immediately.+--   * '(>>=)' is exception handling:+--     The first value throws an exception,+--     while the Kleisli arrow handles the exception+--     and produces a new signal function,+--     which can throw exceptions in a different type. newtype MSFExcept m a b e = MSFExcept { runMSFExcept :: MSF (ExceptT e m) a b } +-- | An alias for the |MSFExcept| constructor,+-- used to enter the |MSFExcept| monad context.+-- Execute an 'MSF' in 'ExceptT' until it raises an exception. try :: MSF (ExceptT e m) a b -> MSFExcept m a b e try = MSFExcept @@ -115,13 +144,19 @@ currentInput :: Monad m => MSFExcept m e b e currentInput = try throwS +-- | Functor instance for MSFs on the 'Either' monad. Fmapping is the same as+-- applying a transformation to the 'Left' values. instance Monad m => Functor (MSFExcept m a b) where   fmap = liftM +-- | Applicative instance for MSFs on the 'Either' monad. The function 'pure'+-- throws an exception. instance Monad m => Applicative (MSFExcept m a b) where   pure = MSFExcept . throw   (<*>) = ap +-- | Monad instance for 'MSFExcept'. Bind uses the exception as the "return"+-- value in the monad. instance Monad m => Monad (MSFExcept m a b) where   MSFExcept msf >>= f = MSFExcept $ MSF $ \a -> do     cont <- lift $ runExceptT $ unMSF msf a@@ -129,8 +164,10 @@       Left e          -> unMSF (runMSFExcept $ f e) a       Right (b, msf') -> return (b, runMSFExcept $ try msf' >>= f) +-- | The empty type. As an exception type, it encodes "no exception possible". data Empty +-- | If no exception can occur, the 'MSF' can be executed without the 'ExceptT' layer. safely :: Monad m => MSFExcept m a b Empty -> MSF m a b safely (MSFExcept msf) = safely' msf   where@@ -138,12 +175,18 @@       Right (b, msf') <- runExceptT $ unMSF msf a       return (b, safely' msf') +-- | An 'MSF' without an 'ExceptT' layer never throws an exception,+--   and can thus have an arbitrary exception type. safe :: Monad m => MSF m a b -> MSFExcept m a b e safe = try . liftMSFTrans +-- | Inside the 'MSFExcept' monad, execute an action of the wrapped monad.+--   This passes the last input value to the action,+--   but doesn't advance a tick. once :: Monad m => (a -> m e) -> MSFExcept m a b e once f = try $ arrM (lift . f) >>> throwS +-- | Variant of 'once' without input. once_ :: Monad m => m e -> MSFExcept m a b e once_ = once . const @@ -155,10 +198,3 @@   (b, e) <- arrM (lift . f) -< a   _      <- throwOn'        -< (n > (1 :: Int), e)   returnA                   -< b--tagged :: Monad m => MSF (ExceptT e1 m) a b -> MSF (ExceptT e2 m) (a, e2) b-tagged msf = MSF $ \(a, e2) -> ExceptT $ do-  cont <- runExceptT $ unMSF msf a-  case cont of-    Left  _e1       -> return $ Left e2-    Right (b, msf') -> return $ Right (b, tagged msf')
src/Control/Monad/Trans/MSF/GenLift.hs view
@@ -1,10 +1,21 @@ {-# LANGUAGE Rank2Types          #-}++-- | More generic lifting combinators.+--+-- This module contains more generic lifting combinators. It includes several+-- implementations, and obviously should be considered work in progress.  The+-- goal is to make this both simple and conceptually understandable. module Control.Monad.Trans.MSF.GenLift where  import Control.Applicative import Data.MonadicStreamFunction --- * Attempt at writing a more generic MSF lifting combinator.  This is+-- | Lifting combinator to move from one monad to another, if one has a+-- function to run computations in one monad into another. Note that, unlike a+-- polymorphic lifting function @forall a . m a -> m1 a@, this auxiliary+-- function needs to be a bit more structured.++-- Attempt at writing a more generic MSF lifting combinator.  This is -- here only to make it easier to find, in a perfect world we'd move -- this to a different module/branch, or at least to the bottom of the -- file.@@ -57,7 +68,12 @@   (b, msf') <- f (unMSF msf) a   return (b, lifterS f msf') --- ** Another wrapper idea+-- | Lifting combinator to move from one monad to another, if one has a+-- function to run computations in one monad into another. Note that, unlike a+-- polymorphic lifting function @forall a . m a -> m1 a@, this auxiliary+-- function needs to be a bit more structured, although less structured than+-- 'lifterS'.+ transS :: (Monad m1, Monad m2)        => (a2 -> m1 a1)        -> (forall c. a2 -> m1 (b1, c) -> m2 (b2, c))@@ -66,7 +82,11 @@     (b2, msf') <- transformOutput a2 $ unMSF msf =<< transformInput a2     return (b2, transS transformInput transformOutput msf') --- ** A more general lifting mechanism that enables recovery.+-- | Lifting combinator to move from one monad to another, if one has a+-- function to run computations in one monad into another. Note that, unlike a+-- polymorphic lifting function @forall a . m a -> m1 a@, this auxiliary+-- function needs to be a bit more structured, although less structured than+-- 'lifterS'. transG1 :: (Monad m1, Functor m2, Monad m2)         => (a2 -> m1 a1)         -> (forall c. a2 -> m1 (b1, c) -> m2 (b2, c))@@ -77,6 +97,10 @@       -- transformOutput' :: forall c. a2 -> m1 (b1, c) -> m2 (b2, Maybe c)       transformOutput' a b = second Just <$> transformOutput a b +-- | More general lifting combinator that enables recovery. Note that, unlike a+-- polymorphic lifting function @forall a . m a -> m1 a@, this auxiliary+-- function needs to be a bit more structured, and produces a Maybe value. The+-- previous MSF is used if a new one is not produced. transG :: (Monad m1, Monad m2)        => (a2 -> m1 a1)        -> (forall c. a2 -> m1 (b1, c) -> m2 (b2, Maybe c))@@ -100,17 +124,15 @@ --                  [msf''] -> return (b2, transGN transformInput transformOutput msf'') --                  ms      -> --- ** Wrapping/unwrapping--- -- IP: Alternative formulation (typechecks just fine): -- -- FIXME: The foralls may get in the way. They may not be necessary.  MB -- raised the issue already for similar code in Core. ---type Wrapper   m1 m2 t1 t2 = forall a b . (t1 a -> m2 b     ) -> (a    -> m1 (t2 b))-type Unwrapper m1 m2 t1 t2 = forall a b . (a    -> m1 (t2 b)) -> (t1 a -> m2 b     )+-- type Wrapper   m1 m2 t1 t2 = forall a b . (t1 a -> m2 b     ) -> (a    -> m1 (t2 b))+-- type Unwrapper m1 m2 t1 t2 = forall a b . (a    -> m1 (t2 b)) -> (t1 a -> m2 b     ) -- -- Helper type, for when we need some identity * -> * type constructor that -- does not get in the way. ---type Id a = a+-- type Id a = a
src/Control/Monad/Trans/MSF/Maybe.hs view
@@ -1,5 +1,10 @@ {-# LANGUAGE Arrows              #-} {-# LANGUAGE Rank2Types          #-}+{- |+The 'Maybe' monad is very versatile. It can stand for default arguments,+for absent values, and for (nondescript) exceptions.+The latter viewpoint is most natural in the context of 'MSF's.+-} module Control.Monad.Trans.MSF.Maybe   ( module Control.Monad.Trans.MSF.Maybe   , module Control.Monad.Trans.Maybe@@ -13,45 +18,42 @@ import Control.Monad.Trans.MSF.GenLift import Data.MonadicStreamFunction -runMaybeS'' :: Monad m => MSF (MaybeT m) a b -> MSF m a (Maybe b)-runMaybeS'' = transG transformInput transformOutput-  where-    transformInput       = return-    transformOutput _ m1 = do r <- runMaybeT m1-                              case r of-                                Nothing     -> return (Nothing, Nothing)-                                Just (b, c) -> return (Just b,  Just c)----- * Throwing Nothing as an exception ("exiting")+-- * Throwing 'Nothing' as an exception ("exiting") +-- | Throw the exception immediately. exit :: Monad m => MSF (MaybeT m) a b exit = MSF $ const $ MaybeT $ return Nothing +-- | Throw the exception when the condition becomes true on the input. exitWhen :: Monad m => (a -> Bool) -> MSF (MaybeT m) a a exitWhen condition = go   where     go = MSF $ \a -> MaybeT $ return $                        if condition a then Nothing else Just (a, go) +-- | Exit when the incoming value is 'True'. exitIf :: Monad m => MSF (MaybeT m) Bool () exitIf = MSF $ \b -> MaybeT $ return $ if b then Nothing else Just ((), exitIf) --- Just a is passed along, Nothing causes the whole MSF to exit+-- | @Just a@ is passed along, 'Nothing' causes the whole 'MSF' to exit. maybeExit :: Monad m => MSF (MaybeT m) (Maybe a) a-maybeExit = MSF $ MaybeT . return . fmap (\x -> (x, maybeExit))+maybeExit = inMaybeT +-- | Embed a 'Maybe' value in the 'MaybeT' layer. Identical to 'maybeExit'. inMaybeT :: Monad m => MSF (MaybeT m) (Maybe a) a inMaybeT = arrM $ MaybeT . return + -- * Catching Maybe exceptions +-- | Run the first @msf@ until the second one produces 'True' from the output of the first. untilMaybe :: Monad m => MSF m a b -> MSF m b Bool -> MSF (MaybeT m) a b untilMaybe msf cond = proc a -> do-  b <- liftMSFTrans msf -< a+  b <- liftMSFTrans msf  -< a   c <- liftMSFTrans cond -< b   inMaybeT -< if c then Nothing else Just b +-- | When an exception occurs in the first 'msf', the second 'msf' is executed from there. catchMaybe :: Monad m => MSF (MaybeT m) a b -> MSF m a b -> MSF m a b catchMaybe msf1 msf2 = MSF $ \a -> do   cont <- runMaybeT $ unMSF msf1 a@@ -67,7 +69,9 @@ listToMaybeS :: Monad m => [b] -> MSF (MaybeT m) a b listToMaybeS = foldr iPost exit --- * Running MaybeT+-- * Running 'MaybeT'+-- | Remove the 'MaybeT' layer by outputting 'Nothing' when the exception occurs.+--   The continuation in which the exception occurred is then tested on the next input. runMaybeS :: Monad m => MSF (MaybeT m) a b -> MSF m a (Maybe b) runMaybeS msf = go   where@@ -77,36 +81,19 @@              Just (b, msf') -> return (Just b, runMaybeS msf')              Nothing        -> return (Nothing, go) --- mapMaybeS msf == runMaybeS (inMaybeT >>> lift mapMaybeS)+-- | Different implementation, to study performance.+runMaybeS'' :: Monad m => MSF (MaybeT m) a b -> MSF m a (Maybe b)+runMaybeS'' = transG transformInput transformOutput+  where+    transformInput       = return+    transformOutput _ m1 = do r <- runMaybeT m1+                              case r of+                                Nothing     -> return (Nothing, Nothing)+                                Just (b, c) -> return (Just b,  Just c) -{--maybeS :: Monad m => MSF m a (Maybe b) -> MSF (MaybeT m) a b-maybeS msf = MSF $ \a -> MaybeT $ return $ unMSF msf a--- maybeS msf == lift msf >>> inMaybeT--}+-- mapMaybeS msf == runMaybeS (inMaybeT >>> lift mapMaybeS)  {---- MB: Doesn't typecheck, I don't know why------ IP: Because of the forall in runTS.------ From the action runMaybeT msfaction it does not know that--- the second element of the pair in 'thing' will be a continuation.------ The first branch of the case works because you are passing the--- msf' as is.------ In the second one, you are passing msf, which has the specific type--- MSF (MaybeT m) a b.------ Two things you can try (to help you see that this is indeed why GHC is--- complaining):---   - Make the second continuation undefined. Then it typechecks.---   - Use ScopedTypeVariables and a let binding to type msf' in the---   first branch of the case selector. It'll complain about the type---   of msf' if you say it's forcibly a MSF (MaybeT m) a b.---- runMaybeS'' :: Monad m => MSF (MaybeT m) a b -> MSF m a (Maybe b) runMaybeS'' msf = transS transformInput transformOutput msf   where
src/Control/Monad/Trans/MSF/Reader.hs view
@@ -1,51 +1,86 @@ {-# LANGUAGE Rank2Types          #-}++-- | MSFs with a Reader monadic layer.+--+-- This module contains functions to work with MSFs that include a 'Reader'+-- monadic layer. This includes functions to create new MSFs that include an+-- additional layer, and functions to flatten that layer out of the MSF's+-- transformer stack. module Control.Monad.Trans.MSF.Reader-  ( module Control.Monad.Trans.MSF.Reader-  , module Control.Monad.Trans.Reader+  ( module Control.Monad.Trans.Reader+  -- * Reader MSF wrapping/unwrapping.+  , readerS+  , runReaderS+  , runReaderS_+  -- ** Alternative implementation using internal type.+  , readerS'+  , runReaderS'+  -- ** Alternative implementation using generic lifting.+  , runReaderS''   ) where  -- External import Control.Monad.Trans.Reader   hiding (liftCallCC, liftCatch) -- Avoid conflicting exports - -- Internal import Control.Monad.Trans.MSF.GenLift import Data.MonadicStreamFunction +-- * Reader MSF wrapping/unwrapping --- * Reader monad+-- | Build an MSF in the 'Reader' monad from one that takes the reader+-- environment as an extra input. This is the opposite of 'runReaderS'. readerS :: Monad m => MSF m (s, a) b -> MSF (ReaderT s m) a b readerS msf = MSF $ \a -> do   (b, msf') <- ReaderT $ \s -> unMSF msf (s, a)   return (b, readerS msf') +-- | Build an MSF that takes an environment as an extra input from one on the+-- 'Reader' monad. This is the opposite of 'readerS'. runReaderS :: Monad m => MSF (ReaderT s m) a b -> MSF m (s, a) b runReaderS msf = MSF $ \(s,a) -> do   (b, msf') <- runReaderT (unMSF msf a) s   return (b, runReaderS msf') --- ** Alternative wrapping/unwrapping MSF combinators using generic lifting -runReaderS' :: Monad m => MSF (ReaderT s m) a b -> MSF m (s, a) b-runReaderS' = lifterS unwrapReaderT+-- | Build an MSF /function/ that takes a fixed environment as additional+-- input, from an MSF in the 'Reader' monad.+--+-- This should be always equal to:+--+-- @+-- runReaderS_ msf s = arr (\a -> (s,a)) >>> runReaderS msf+-- @+--+-- although possibly more efficient. +runReaderS_ :: Monad m => MSF (ReaderT s m) a b -> s -> MSF m a b+runReaderS_ msf s = MSF $ \a -> do+  (b, msf') <- runReaderT (unMSF msf a) s+  return (b, runReaderS_ msf' s) -type ReaderWrapper   s m = Wrapper   (ReaderT s m) m ((,) s) Id-type ReaderUnwrapper s m = Unwrapper (ReaderT s m) m ((,) s) Id--- and use the types:--- wrapReaderT   :: ReaderWrapper s m--- unwrapReaderT :: ReaderUnwrapper s m+-- ** Alternative implementation using internal type. +-- TODO: One one should exist, ideally.++-- | Alternative version of 'readerS'.+readerS' :: Monad m => MSF m (s, a) b -> MSF (ReaderT s m) a b+readerS' = lifterS wrapReaderT++-- | Alternative version of 'runReaderS' wrapping/unwrapping functions.+runReaderS' :: Monad m => MSF (ReaderT s m) a b -> MSF m (s, a) b+runReaderS' = lifterS unwrapReaderT+ wrapReaderT :: ((s, a) -> m b) -> a -> ReaderT s m b wrapReaderT g i = ReaderT $ g . flip (,) i  unwrapReaderT :: (a -> ReaderT s m b) -> (s, a) -> m b unwrapReaderT g i = uncurry (flip runReaderT) $ second g i -readerS' :: Monad m => MSF m (s, a) b -> MSF (ReaderT s m) a b-readerS' = lifterS wrapReaderT+-- ** Alternative implementation using generic lifting. +-- | Alternative version of 'runReaderS'. runReaderS'' :: Monad m => MSF (ReaderT s m) a b -> MSF m (s, a) b runReaderS'' = transG transformInput transformOutput   where@@ -62,11 +97,13 @@     transformOutput _ = lift -} --- ** Auxiliary functions related to ReaderT --- IP: Is runReaderS_ msf s = arr (\a -> (s,a)) >>> runReaderS msf ?--- MB: Yes, but possibly more efficient.-runReaderS_ :: Monad m => MSF (ReaderT s m) a b -> s -> MSF m a b-runReaderS_ msf s = MSF $ \a -> do-  (b, msf') <- runReaderT (unMSF msf a) s-  return (b, runReaderS_ msf' s)+-- Another alternative:+--+-- type ReaderWrapper   s m = Wrapper   (ReaderT s m) m ((,) s) Id+-- type ReaderUnwrapper s m = Unwrapper (ReaderT s m) m ((,) s) Id+--+-- and use the types:+--+-- wrapReaderT   :: ReaderWrapper s m+-- unwrapReaderT :: ReaderUnwrapper s m
src/Control/Monad/Trans/MSF/State.hs view
@@ -1,7 +1,24 @@-{-# LANGUAGE Rank2Types          #-}+{-# LANGUAGE Rank2Types #-}+-- | MSFs with a State monadic layer.+--+-- This module contains functions to work with MSFs that include a 'State'+-- monadic layer. This includes functions to create new MSFs that include an+-- additional layer, and functions to flatten that layer out of the MSF's+-- transformer stack. module Control.Monad.Trans.MSF.State-  ( module Control.Monad.Trans.MSF.State-  , module Control.Monad.Trans.State.Strict+  ( module Control.Monad.Trans.State.Strict+  -- * State MSF running/wrapping/unwrapping+  , stateS+  , runStateS+  , runStateS_+  , runStateS__+  -- ** Alternative implementation using 'lifterS'+  , stateS'+  , runStateS'+  -- ** Alternative implementation using 'transS'+  , runStateS''+  -- ** Alternative implementation using 'transG'+  , runStateS'''   ) where  -- External@@ -13,44 +30,64 @@ import Control.Monad.Trans.MSF.GenLift import Data.MonadicStreamFunction -+-- * State MSF running/wrapping/unwrapping --- * Running and wrapping+-- | Build an MSF in the 'State' monad from one that takes the state as an+-- extra input. This is the opposite of 'runStateS'. stateS :: Monad m => MSF m (s, a) (s, b) -> MSF (StateT s m) a b stateS msf = MSF $ \a -> StateT $ \s -> do     ((s', b), msf') <- unMSF msf (s, a)     return ((b, stateS msf'), s') +-- | Build an MSF that takes a state as an extra input from one on the+-- 'State' monad. This is the opposite of 'stateS'. runStateS :: Monad m => MSF (StateT s m) a b -> MSF m (s, a) (s, b) runStateS msf = MSF $ \(s, a) -> do     ((b, msf'), s') <- runStateT (unMSF msf a) s     return ((s', b), runStateS msf') --- * Auxiliary functions+-- | Build an MSF /function/ that takes a fixed state as additional input, from+-- an MSF in the 'State' monad, and outputs the new state with every+-- transformation step.+--+-- This should be always equal to:+--+-- @+-- runStateS_ msf s = feedback s $ runStateS msf >>> arr (\(s,b) -> ((s,b), s))+-- @+--+-- although possibly more efficient. --- IP: Is runStateS_ msf s = feedback s $ runStateS msf >>> arr (\(s,b) -> ((s,b), s)) ?+ runStateS_ :: Monad m => MSF (StateT s m) a b -> s -> MSF m a (s, b) runStateS_ msf s = MSF $ \a -> do     ((b, msf'), s') <- runStateT (unMSF msf a) s     return ((s', b), runStateS_ msf' s') --- IP: Is runStateS__ msf s = feedback s $ runStateS msf >>> arr (\(s,b) -> (b, s)) ?+-- | Build an MSF /function/ that takes a fixed state as additional+-- input, from an MSF in the 'State' monad.+--+-- This should be always equal to:+--+-- @+-- runStateS__ msf s = feedback s $ runStateS msf >>> arr (\(s,b) -> (b, s))+-- @+--+-- although possibly more efficient.++ runStateS__ :: Monad m => MSF (StateT s m) a b -> s -> MSF m a b runStateS__ msf s = MSF $ \a -> do     ((b, msf'), s') <- runStateT (unMSF msf a) s     return (b, runStateS__ msf' s') +-- * Alternative implementations+--+-- ** Alternative using running/wrapping MSF combinators using generic lifting -runStateS''' :: (Functor m, Monad m) => MSF (StateT s m) a b -> MSF m (s, a) (s, b)-runStateS''' = transG transformInput transformOutput-  where-    transformInput  (_, a)           = return a-    transformOutput (s, _) msfaction = sym <$> runStateT msfaction s-    sym ((b, msf), s)                = ((s, b), Just msf)+-- ** Alternative using 'lifterS'. --- * Alternative running/wrapping MSF combinators using generic lifting------ IPerez: TODO: Is this exactly the same as stateS?+-- | Alternative implementation of 'stateS' using 'lifterS'. stateS' :: (Functor m, Monad m) => MSF m (s, a) (s, b) -> MSF (StateT s m) a b stateS' = lifterS (\g i -> StateT ((resort <$>) . g . flip (,) i))  where resort ((s, b), ct) = ((b, ct), s)@@ -60,11 +97,14 @@ --   ((s', b), msf') <- f (s, a) --   return ((b, msf'), s') +-- | Alternative implementation of 'runStateS' using 'lifterS'. runStateS' :: (Functor m, Monad m) => MSF (StateT s m) a b -> MSF m (s, a) (s, b) runStateS' = lifterS (\g i -> resort <$> uncurry (flip runStateT) (second g i))  where resort ((b, msf), s) = ((s, b), msf) +-- ** Alternative using 'transS'. +-- | Alternative implementation of 'runStateS' using 'transS'. runStateS'' :: (Functor m, Monad m) => MSF (StateT s m) a b -> MSF m (s, a) (s, b) runStateS'' = transS transformInput transformOutput   where@@ -80,3 +120,13 @@     transformOutput (s, _) = do         put s -}++-- ** Alternative using 'transG'.++-- | Alternative implementation of 'runStateS' using 'transG'.+runStateS''' :: (Functor m, Monad m) => MSF (StateT s m) a b -> MSF m (s, a) (s, b)+runStateS''' = transG transformInput transformOutput+  where+    transformInput  (_, a)           = return a+    transformOutput (s, _) msfaction = sym <$> runStateT msfaction s+    sym ((b, msf), s)                = ((s, b), Just msf)
src/Control/Monad/Trans/MSF/Writer.hs view
@@ -1,6 +1,22 @@+-- | MSFs with a Writer monadic layer.+--+-- This module contains functions to work with MSFs that include a 'Writer'+-- monadic layer. This includes functions to create new MSFs that include an+-- additional layer, and functions to flatten that layer out of the MSF's+-- transformer stack. module Control.Monad.Trans.MSF.Writer-  ( module Control.Monad.Trans.MSF.Writer-  , module Control.Monad.Trans.Writer.Strict+  ( module Control.Monad.Trans.Writer.Strict+  -- * Writer MSF running \/ wrapping \/ unwrapping+  , writerS+  , runWriterS++  -- ** Alternative implementation using 'lifterS'+  , writerS'+  , runWriterS'++  -- ** Alternative implementation using 'transS'+  , writerS''+  , runWriterS''   ) where  -- External@@ -8,33 +24,44 @@ import Control.Monad.Trans.Class import Control.Monad.Trans.Writer.Strict   hiding (liftCallCC, liftCatch, pass) -- Avoid conflicting exports--- import Data.Monoid+import Data.Monoid  -- Internal import Control.Monad.Trans.MSF.GenLift import Data.MonadicStreamFunction --- * Writer monad+-- * Writer MSF running/wrapping/unwrapping++-- | Build an MSF in the 'Writer' monad from one that produces the log as an+-- extra output. This is the opposite of 'runWriterS'. writerS :: (Monad m, Monoid s) => MSF m a (s, b) -> MSF (WriterT s m) a b writerS msf = MSF $ \a -> do     ((s, b), msf') <- lift $ unMSF msf a     tell s     return (b, writerS msf') +-- | Build an MSF that produces the log as an extra output from one on the+-- 'Writer' monad. This is the opposite of 'writerS'. runWriterS :: Monad m => MSF (WriterT s m) a b -> MSF m a (s, b) runWriterS msf = MSF $ \a -> do     ((b, msf'), s') <- runWriterT $ unMSF msf a     return ((s', b), runWriterS msf') +-- * Alternative running/wrapping MSF combinators --- * Alternative running/wrapping MSF combinators using generic lifting+-- ** Alternative implementation using 'lifterS' +-- | Alternative implementation of 'writerS' using 'lifterS'. writerS' :: (Monad m, Monoid s) => MSF m a (s, b) -> MSF (WriterT s m) a b writerS' = lifterS wrapMSFWriterT +-- | Alternative implementation of 'runWriterS' using 'lifterS'. runWriterS' :: (Monoid s, Functor m, Monad m) => MSF (WriterT s m) a b -> MSF m a (s, b) runWriterS' = lifterS unwrapMSFWriterT +-- ** Alternative implementation using 'transS'++-- | Alternative implementation of 'writerS' using 'transS'. writerS'' :: (Monad m, Monoid w) => MSF m a (w, b) -> MSF (WriterT w m) a b writerS'' = transS transformInput transformOutput   where@@ -44,6 +71,7 @@         tell w         return (b, msf') +-- | Alternative implementation of 'runWriterS' using 'transS'. runWriterS'' :: (Monoid s, Functor m, Monad m) => MSF (WriterT s m) a b -> MSF m a (s, b) runWriterS'' = transS transformInput transformOutput   where
src/Data/MonadicStreamFunction/Core.hs view
@@ -71,6 +71,7 @@  -- Instances +-- | Instance definition for 'Category'. Defines 'id' and '.'. instance Monad m => Category (MSF m) where   id = go     where go = MSF $ \a -> return (a, go)@@ -80,6 +81,7 @@     let sf' = sf2' . sf1'     c `seq` return (c, sf') +-- | 'Arrow' instance for MSFs. instance Monad m => Arrow (MSF m) where    arr f = go@@ -89,12 +91,14 @@     (b, sf') <- unMSF sf a     b `seq` return ((b, c), first sf') +-- | Functor instance for MSFs. instance Functor m => Functor (MSF m a) where   -- fmap f msf == msf >>> arr f   fmap f msf = MSF $ fmap fS . unMSF msf     where       fS (b, cont) = (f b, fmap f cont) +-- | Applicative instance for MSFs. instance (Functor m, Monad m) => Applicative (MSF m a) where   -- It is possible to define this instance with only Applicative m   pure = arr . const@@ -198,8 +202,8 @@ -- | Switching applies one MSF until it produces a 'Just' output, and then -- "turns on" a continuation and runs it. ----- A more advanced and comfortable approach to switching is givin by Exceptions--- in "Control.Monad.Trans.MSF.Except"+-- A more advanced and comfortable approach to switching is given by Exceptions+-- in 'Control.Monad.Trans.MSF.Except' switch :: Monad m => MSF m a (b, Maybe c) -> (c -> MSF m a b) -> MSF m a b switch sf f = MSF $ \a -> do   ((b, c), sf') <- unMSF sf a@@ -223,10 +227,10 @@ -- if the MSF produces Nothing at any point, so the output stream cannot -- consumed progressively. ----- To explore the output progressively, use liftMSF and (>>>), together+-- To explore the output progressively, use 'liftMSF' and '(>>>)'', together -- with some action that consumes/actuates on the output. ----- This is called "runSF" in Liu, Cheng, Hudak, "Causal Commutative Arrows and+-- This is called 'runSF' in Liu, Cheng, Hudak, "Causal Commutative Arrows and -- Their Optimization" embed :: Monad m => MSF m a b -> [a] -> m [b] embed _  []     = return []@@ -235,12 +239,15 @@   bs       <- embed sf' as   return (b:bs) --- | Run an MSF indefinitely passing a unit-carrying input stream.+-- | Run an 'MSF' indefinitely passing a unit-carrying input stream. reactimate :: Monad m => MSF m () () -> m () reactimate sf = do   (_, sf') <- unMSF sf ()   reactimate sf' +-- | Run an 'MSF' indefinitely passing a unit-carrying input stream.+-- A more high-level approach to this would be the use of 'MaybeT'+-- in 'Control.Monad.Trans.MSF.Maybe'. -- | Run an MSF indefinitely passing a unit-carrying input stream.  -- TODO: A more high-level approach to this would be the use of MaybeT in
src/Data/MonadicStreamFunction/Instances/ArrowChoice.hs view
@@ -9,6 +9,7 @@  import Data.MonadicStreamFunction.Core +-- | 'ArrowChoice' instance for MSFs. instance Monad m => ArrowChoice (MSF m) where   left :: MSF m a b -> MSF m (Either a c) (Either b c)   left sf = MSF f
src/Data/MonadicStreamFunction/Instances/ArrowLoop.hs view
@@ -14,6 +14,8 @@ import Control.Arrow import Control.Monad.Fix +-- | 'ArrowLoop' instance for MSFs. The monad must be an instance of+-- 'MonadFix'. instance (Monad m, MonadFix m) => ArrowLoop (MSF m) where   loop :: MSF m (b, d) (c, d) -> MSF m b c   loop sf = MSF $ \a -> do
src/Data/MonadicStreamFunction/Instances/ArrowPlus.hs view
@@ -11,8 +11,12 @@  import Data.MonadicStreamFunction.Core +-- | Instance of 'ArrowZero' for Monadic Stream Functions ('MSF').+--   The monad must be an instance of 'MonadPlus'. instance (Monad m, MonadPlus m) => ArrowZero (MSF m) where   zeroArrow = MSF $ const mzero +-- | Instance of 'ArrowPlus' for Monadic Stream Functions ('MSF').+--   The monad must be an instance of 'MonadPlus'. instance (Monad m, MonadPlus m) => ArrowPlus (MSF m) where   sf1 <+> sf2 = MSF $ \a -> unMSF sf1 a `mplus` unMSF sf2 a
src/Data/MonadicStreamFunction/Instances/Num.hs view
@@ -1,10 +1,31 @@ {-# LANGUAGE TypeFamilies         #-} {-# OPTIONS_GHC -fno-warn-orphans #-}++-- | Number instances for MSFs that produce numbers. This allows you to use+-- numeric operators with MSFs that output numbers, for example, you can write:+--+-- @+-- msf1 :: MSF Input Double -- defined however you want+-- msf2 :: MSF Input Double -- defined however you want+-- msf3 :: MSF Input Double+-- msf3 = msf1 + msf2+-- @+--+-- instead of+--+-- @+-- msf3 = (msf1 &&& msf2) >>> arr (uncurry (+))+-- @+--+-- Instances are provided for the type classes 'Num', 'Fractional'+-- and 'Floating'.+ module Data.MonadicStreamFunction.Instances.Num where  import Control.Arrow.Util import Data.MonadicStreamFunction.Core +-- | 'Num' instance for MSFs. instance (Monad m, Num b) => Num (MSF m a b) where   (+)         = elementwise2 (+)   (-)         = elementwise2 (-)@@ -14,11 +35,13 @@   negate      = elementwise negate   fromInteger = constantly . fromInteger +-- | 'Fractional' instance for MSFs. instance (Monad m, Fractional b) => Fractional (MSF m a b) where   fromRational = constantly . fromRational   (/)          = elementwise2 (/)   recip        = elementwise recip +-- | 'Floating' instance for MSFs. instance (Monad m, Floating b) => Floating (MSF m a b) where   pi      = constantly   pi   exp     = elementwise  exp
src/Data/MonadicStreamFunction/Instances/VectorSpace.hs view
@@ -1,5 +1,24 @@ {-# LANGUAGE TypeFamilies         #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+-- | 'VectorSpace' instances for MSFs that produce vector spaces. This allows+-- you to use vector operators with MSFs that output vectors, for example, you+-- can write:+--+-- @+-- msf1 :: MSF Input (Double, Double) -- defined however you want+-- msf2 :: MSF Input (Double, Double) -- defined however you want+-- msf3 :: MSF Input (Double, Double)+-- msf3 = msf1 ^+^ msf2+-- @+--+-- instead of+--+-- @+-- msf3 = (msf1 &&& msf2) >>> arr (uncurry (^+^))+-- @+--+--+-- Instances are provided for the type classes 'RModule' and 'VectorSpace'. module Data.MonadicStreamFunction.Instances.VectorSpace where  import Control.Arrow@@ -8,6 +27,8 @@ import Data.VectorSpace  -- These conflict with Data.VectorSpace.Instances++-- | R-module instance for MSFs. instance (Monad m, RModule v) => RModule (MSF m a v) where   type Groundring (MSF m a v) = Groundring v   zeroVector   = constantly zeroVector@@ -16,5 +37,6 @@   (^+^)        = elementwise2 (^+^)   (^-^)        = elementwise2 (^-^) +-- | Vector-space instance for MSFs. instance (Monad m, VectorSpace v) => VectorSpace (MSF m a v) where   msf ^/ r = msf >>^ (^/ r)
src/Data/MonadicStreamFunction/Parallel.hs view
@@ -1,3 +1,5 @@+-- | Versions of arrow combinators that run things in parallel using 'par', if+-- possible. module Data.MonadicStreamFunction.Parallel where  -- External@@ -9,14 +11,6 @@  -- | Run two MSFs in parallel, taking advantage of parallelism if --   possible. This is the parallel version of '(***)'.---- IPerez: This should be similar to the following:--- (msf1 *** msf2) >>> parS--- where parS             = arr parTuple---       parTuple p@(a,b) = (a `par` b `pseq` p)--- Manuel: but we added strictness annotations to first--- and so (***) might be strict in both arguments and not take--- full advantage of parallelism.  (*|*) :: Monad m => MSF m a b -> MSF m c d -> MSF m (a, c) (b, d) msf1 *|* msf2 = MSF $ \(a, c) -> do
src/Data/MonadicStreamFunction/Util.hs view
@@ -1,3 +1,4 @@+-- | Useful auxiliary functions and definitions. module Data.MonadicStreamFunction.Util where  -- External@@ -13,51 +14,40 @@ import Data.MonadicStreamFunction.Core import Data.VectorSpace --- * Useful aliases-type MStream m a = MSF m () a-type MSink   m a = MSF m a ()----- * Stateful accumulation--accumulateWith :: Monad m => (a -> s -> s) -> s -> MSF m a s-accumulateWith f s0 = feedback s0 $ arr g-  where-    g (a, s) = let s' = f a s in (s', s')---- ** Accumulation for monoids--mappendS :: (Monoid n, Monad m) => MSF m n n-mappendS = mappendFrom mempty-{-# INLINE mappendS #-}--mappendFrom :: (Monoid n, Monad m) => n -> MSF m n n-mappendFrom = accumulateWith mappend+-- * Streams and sinks --- ** Accumulation for VectorSpace instances+-- | A stream is an MSF that produces outputs ignoring the input. It can+-- obtain the values from a monadic context.+type MStream m a = MSF m () a -sumFrom :: (RModule v, Monad m) => v -> MSF m v v-sumFrom = accumulateWith (^+^)+-- | A stream is an MSF that produces outputs producing no output. It can+-- consume the values with side effects.+type MSink   m a = MSF m a () -sumS :: (RModule v, Monad m) => MSF m v v-sumS = sumFrom zeroVector+-- * Lifting -count :: (Num n, Monad m) => MSF m a n-count = arr (const 1) >>> accumulateWith (+) 0+-- | Pre-inserts an input sample.+{-# DEPRECATED insert "Don't use this. arrM id instead" #-}+insert :: Monad m => MSF m (m a) a+insert = arrM id --- * Generating Signals+-- | Lifts a computation into a Stream.+arrM_ :: Monad m => m b -> MSF m a b+arrM_ = arrM . const -unfold :: Monad m => (a -> (b,a)) -> a -> MSF m () b-unfold f a = MSF $ \_ -> let (b,a') = f a in b `seq` return (b, unfold f a')--- unfold f x = feedback x (arr (snd >>> f))+-- | Lift the first MSF into the monad of the second.+(^>>>) :: MonadBase m1 m2 => MSF m1 a b -> MSF m2 b c -> MSF m2 a c+sf1 ^>>> sf2 = liftMSFBase sf1 >>> sf2+{-# INLINE (^>>>) #-} -repeatedly :: Monad m => (a -> a) -> a -> MSF m () a-repeatedly f = repeatedly'- where repeatedly' a = MSF $ \() -> let a' = f a in a' `seq` return (a, repeatedly' a')--- repeatedly f x = feedback x (arr (f >>> \x -> (x,x)))+-- | Lift the second MSF into the monad of the first.+(>>>^) :: MonadBase m1 m2 => MSF m2 a b -> MSF m1 b c -> MSF m2 a c+sf1 >>>^ sf2 = sf1 >>> liftMSFBase sf2+{-# INLINE (>>>^) #-}  -- * Analogues of map and fmap +-- | Apply an MSF to every input. mapMSF :: Monad m => MSF m a b -> MSF m [a] [b] mapMSF = MSF . consume   where@@ -68,6 +58,8 @@       (bs, sf'') <- consume sf' as       b `seq` return (b:bs, sf'') +-- | Apply an MSF to every input. Freezes temporarily if the input is+-- 'Nothing', and continues as soon as a 'Just' is received. mapMaybeS :: Monad m => MSF m a b -> MSF m (Maybe a) (Maybe b) mapMaybeS msf = go   where@@ -77,68 +69,89 @@         return (Just b, mapMaybeS msf')       Nothing -> return (Nothing, go) -- -- * Adding side effects++-- | Applies a function to produce an additional side effect and passes the+-- input unchanged. withSideEffect :: Monad m => (a -> m b) -> MSF m a a withSideEffect method = (id &&& arrM method) >>> arr fst +-- | Produces an additional side effect and passes the input unchanged. withSideEffect_ :: Monad m => m b -> MSF m a a withSideEffect_ method = withSideEffect $ const method --- * Debugging+-- * Delays -traceWith :: (Monad m, Show a) => (String -> m ()) -> String -> MSF m a a-traceWith method msg =-  withSideEffect (method . (msg ++) . show)+-- See also: 'iPre' -trace :: Show a => String -> MSF IO a a-trace = traceWith putStrLn+-- | Preprends a fixed output to an MSF. The first input is completely+-- ignored.+iPost :: Monad m => b -> MSF m a b -> MSF m a b+iPost b sf = MSF $ \_ -> return (b, sf) -traceWhen :: (Monad m, Show a) => (a -> Bool) -> (String -> m ()) -> String -> MSF m a a-traceWhen cond method msg = withSideEffect $ \a ->-  when (cond a) $ method $ msg ++ show a+-- | Preprends a fixed output to an MSF, shifting the output.+next :: Monad m => b -> MSF m a b -> MSF m a b+next b sf = MSF $ \a -> do+  (b', sf') <- unMSF sf a+  return (b, next b' sf')+-- rather, once delay is tested:+-- next b sf = sf >>> delay b -pauseOn :: Show a => (a -> Bool) -> String -> MSF IO a a-pauseOn cond = traceWhen cond $ \s -> print s >> getLine >> return () +-- * Folding --- * Inserting monadic actions into MSFs+-- ** Folding for VectorSpace instances -{-# DEPRECATED insert "Don't use this. arrM id instead" #-}-insert :: Monad m => MSF m (m a) a-insert = arrM id+-- | Count the number of simulation steps. Produces 1, 2, 3,...+count :: (Num n, Monad m) => MSF m a n+count = arr (const 1) >>> accumulateWith (+) 0 -arrM_ :: Monad m => m b -> MSF m a b-arrM_ = arrM . const+-- | Sums the inputs, starting from zero.+sumS :: (RModule v, Monad m) => MSF m v v+sumS = sumFrom zeroVector --- * Lifting from one monad into another+-- | Sums the inputs, starting from an initial vector.+sumFrom :: (RModule v, Monad m) => v -> MSF m v v+sumFrom = accumulateWith (^+^) +-- ** Folding for monoids -(^>>>) :: MonadBase m1 m2 => MSF m1 a b -> MSF m2 b c -> MSF m2 a c-sf1 ^>>> sf2 = liftMSFBase sf1 >>> sf2-{-# INLINE (^>>>) #-}+-- | Accumulate the inputs, starting from 'mempty'.+mappendS :: (Monoid n, Monad m) => MSF m n n+mappendS = mappendFrom mempty+{-# INLINE mappendS #-} -(>>>^) :: MonadBase m1 m2 => MSF m2 a b -> MSF m1 b c -> MSF m2 a c-sf1 >>>^ sf2 = sf1 >>> liftMSFBase sf2-{-# INLINE (>>>^) #-}+-- | Accumulate the inputs, starting from an initial monoid value.+mappendFrom :: (Monoid n, Monad m) => n -> MSF m n n+mappendFrom = accumulateWith mappend --- * Delays and signal overwriting+-- ** Generic folding \/ accumulation --- See also: 'iPre'+-- | Applies a function to the input and an accumulator, outputing the+-- accumulator. Equal to @\f s0 -> feedback s0 $ arr (uncurry f >>> dup)@.+accumulateWith :: Monad m => (a -> s -> s) -> s -> MSF m a s+accumulateWith f s0 = feedback s0 $ arr g+  where+    g (a, s) = let s' = f a s in (s', s') -iPost :: Monad m => b -> MSF m a b -> MSF m a b-iPost b sf = MSF $ \_ -> return (b, sf)+-- * Unfolding -next :: Monad m => b -> MSF m a b -> MSF m a b-next b sf = MSF $ \a -> do-  (b', sf') <- unMSF sf a-  return (b, next b' sf')--- rather, once delay is tested:--- next b sf = sf >>> delay b+-- | Generate outputs using a step-wise generation function and an initial+-- value.+unfold :: Monad m => (a -> (b,a)) -> a -> MSF m () b+unfold f a = MSF $ \_ -> let (b,a') = f a in b `seq` return (b, unfold f a')+-- unfold f x = feedback x (arr (snd >>> f)) --- * Alternative running functions+-- | Generate outputs using a step-wise generation function and an initial+-- value. Version of 'unfold' in which the output and the new accumulator+-- are the same. Should be equal to @\f a -> unfold (f >>> dup) a@.+repeatedly :: Monad m => (a -> a) -> a -> MSF m () a+repeatedly f = repeatedly'+ where repeatedly' a = MSF $ \() -> let a' = f a in a' `seq` return (a, repeatedly' a')+-- repeatedly f x = feedback x (arr (f >>> \x -> (x,x))) +-- * Running functions+ -- | Run an MSF fed from a list, discarding results. Useful when one needs to -- combine effects and streams (i.e., for testing purposes). @@ -146,3 +159,26 @@ -- construts. Move to a non-core module? embed_ :: (Functor m, Monad m) => MSF m a () -> [a] -> m () embed_ msf as = void $ foldM (\sf a -> snd <$> unMSF sf a) msf as++-- * Debugging++-- | Outputs every input sample, with a given message prefix.+trace :: Show a => String -> MSF IO a a+trace = traceWith putStrLn++-- | Outputs every input sample, with a given message prefix, using an+-- auxiliary printing function.+traceWith :: (Monad m, Show a) => (String -> m ()) -> String -> MSF m a a+traceWith method msg =+  withSideEffect (method . (msg ++) . show)++-- | Outputs every input sample, with a given message prefix, using an+-- auxiliary printing function, when a condition is met.+traceWhen :: (Monad m, Show a) => (a -> Bool) -> (String -> m ()) -> String -> MSF m a a+traceWhen cond method msg = withSideEffect $ \a ->+  when (cond a) $ method $ msg ++ show a++-- | Outputs every input sample, with a given message prefix, when a condition+-- is met, and waits for some input \/ enter to continue.+pauseOn :: Show a => (a -> Bool) -> String -> MSF IO a a+pauseOn cond = traceWhen cond $ \s -> print s >> getLine >> return ()
src/Data/VectorSpace.hs view
@@ -11,6 +11,7 @@ -- Portability :  non-portable (GHC extensions) -- -- Vector space type relation and basic instances.+-- Heavily inspired by Yampa's @FRP.Yampa.VectorSpace@ module.  module Data.VectorSpace where @@ -23,15 +24,33 @@ infix 6 `dot` infixl 5 ^+^, ^-^ --- TODO Add laws this should satisfy-+-- | R-modules.+--   A module @v@ over a ring @Groundring v@+--   is an abelian group with a linear multiplication.+--   The hat @^@ denotes the side of an operation+--   on which the vector stands,+--   i.e. @a *^ v@ for @v@ a vector.+--+-- A minimal definition should include the type 'Groundring' and the+-- implementations of 'zeroVector', '^+^', and one of '*^' or '^*'.+--+--   The following laws must be satisfied:+--+--   * @v1 ^+^ v2 == v2 ^+^ v1@+--   * @a *^ zeroVector == zeroVector@+--   * @a *^ (v1 ^+^ v2) == a *^ v1 ^+^ a*^ v2+--   * @a *^ v == v ^* a@+--   * @negateVector v == (-1) *^ v@+--   * @v1 ^-^ v2 == v1 ^+^ negateVector v2@ class Num (Groundring v) => RModule v where     type Groundring v     zeroVector   :: v+     (*^)         :: Groundring v -> v -> v+    (*^)         = flip (^*)+     (^*)         :: v -> Groundring v -> v-    (^*) = flip (*^)-    (*^) = flip (^*)+    (^*)         = flip (*^)      negateVector :: v -> v     negateVector v = (-1) *^ v@@ -41,25 +60,53 @@     (^-^)        :: v -> v -> v     v1 ^-^ v2     = v1 ^+^ negateVector v2 - -- Maybe norm and normalize should not be class methods, in which case -- the constraint on the coefficient space (a) should (or, at least, could) -- be Fractional (roughly a Field) rather than Floating.  -- Minimal instance: zeroVector, (*^), (^+^), dot -- class Fractional (Groundfield v) => VectorSpace v where++-- | A vector space is a module over a field,+--   i.e. a commutative ring with inverses.+--+--   It needs to satisfy the axiom+--   @v ^/ a == (1/a) *^ v@,+--   which is the default implementation. class (Fractional (Groundring v), RModule v) => VectorSpace v where-    (^/)         :: v -> Groundfield v -> v+    (^/) :: v -> Groundfield v -> v     v ^/ a = (1/a) *^ v +-- TODO Why is this not a type synonym?+-- | The ground ring of a vector space is required to be commutative+--   and to possess inverses.+--   It is then called the "ground field".+--   Commutativity amounts to the law @a * b = b * a@,+--   and the existence of inverses is given+--   by the requirement of the 'Fractional' type class. type family Groundfield v :: * type instance Groundfield v = Groundring v +-- | An inner product space is a module with an inner product,+--   i.e. a map @dot@ satisfying+--+--   * @v1 `dot` v2 == v2 `dot` v1@+--   * @(v1 ^+^ v2) `dot` v3 == v1 `dot` v3 ^+^ v2 `dot` v3@+--   * @(a *^ v1) `dot` v2 == a *^ v1 `dot` v2@ class RModule v => InnerProductSpace v where-    dot          :: v -> v -> Groundfield v+  dot :: v -> v -> Groundfield v +-- | A normed space is a module with a norm,+--   i.e. a function @norm@ satisfying+--+--   * @norm (a ^* v) = a ^* norm v@+--   * @norm (v1 ^+^ v2) <= norm v1 ^+^ norm v2@+--     (the "triangle inequality")+--+--   A typical example is @sqrt (v `dot` v)@,+--   for an inner product space. class RModule v => NormedSpace v  where-    norm         :: v -> Groundfield v+  norm :: v -> Groundfield v  {- instance (Floating (Groundfield v), VectorSpace v, InnerProductSpace v) => NormedSpace v where
src/Data/VectorSpace/Fractional.hs view
@@ -2,15 +2,23 @@ {-# LANGUAGE TypeFamilies           #-} {-# LANGUAGE UndecidableInstances   #-} {-# OPTIONS_GHC -fno-warn-orphans   #-}+-- | VectorSpace instances for Num/Fractional types.+--+-- This module includes instances for:+--+--    * 'InnerProductSpace' and 'RModule' for 'Num'+--+--    * 'VectorSpace' for 'Fractional's module Data.VectorSpace.Fractional where --- VectorSpace instances for Num/Fractional types. These sometimes clash with--- user-defined instances.+-- These sometimes clash with user-defined instances. -- (See https://github.com/ivanperez-keera/dunai/issues/11, where this -- module used to be called Data.VectorSpace.Instances)  import Data.VectorSpace +-- | R-module instance for any number, where '^+^ is '+' and multiplication is+-- normal multiplication. instance Num a => RModule a where     type Groundring a = a     zeroVector     = 0@@ -19,8 +27,11 @@     x1 ^+^ x2      = x1 + x2     x1 ^-^ x2      = x1 - x2 +-- | Vector-space instance for any fractional, where vectorial division is+-- normal number division. instance Fractional a => VectorSpace a where     a ^/ x = a / x +-- | Inner-product instance for any number. instance Num a => InnerProductSpace a where     x1 `dot` x2 = x1 * x2
src/Data/VectorSpace/Specific.hs view
@@ -1,16 +1,25 @@ {-# LANGUAGE TypeFamilies         #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+-- | Vector space instances for concrete/specific types.+--+-- This module contains:+--+--     * 'RModule' instances for 'Int', 'Integer', 'Double' and 'Float'.+--+--     * 'VectorSpace' for 'Double' and 'Float'.+ module Data.VectorSpace.Specific where  import Data.VectorSpace -+-- | R-mobule instance for 'Int's. instance RModule Int where     type Groundring Int = Int     (^+^) = (+)     (^*) = (*)     zeroVector = 0 +-- | R-mobule instance for 'Integer's. instance RModule Integer where     type Groundring Integer = Integer     (^+^) = (+)@@ -18,18 +27,22 @@     zeroVector = 0  +-- | R-mobule instance for 'Double's. instance RModule Double where     type Groundring Double = Double     (^+^) = (+)     (^*) = (*)     zeroVector = 0 +-- | R-mobule instance for 'Floating's. instance RModule Float where     type Groundring Float = Float     (^+^) = (+)     (^*) = (*)     zeroVector = 0 +-- | Vector-space instance for 'Double'. instance VectorSpace Double where +-- | Vector-space instance for 'Floating's. instance VectorSpace Float where
src/Data/VectorSpace/Tuples.hs view
@@ -1,25 +1,27 @@ {-# LANGUAGE FlexibleInstances      #-} {-# LANGUAGE TypeFamilies           #-} {-# OPTIONS_GHC -fno-warn-orphans   #-}+-- | Vector space instances for small tuples of 'Fractional'.+--+-- This module contains 'RModule', 'VectorSpace' and 'InnerProductSpace' for+-- tuples of up to five elements.+ module Data.VectorSpace.Tuples where  import Data.VectorSpace ---------------------------------------------------------------------------------- Vector space instances for small tuples of Fractional----------------------------------------------------------------------------------+-- | R-module instance for tuples. instance (Groundring a ~ Groundring b, RModule a, RModule b) => RModule (a, b) where     type Groundring (a, b) = Groundring a     zeroVector = (zeroVector, zeroVector)     (a, b) ^* x = (a ^* x, b ^* x)     (a1, b1) ^+^ (a2, b2) = (a1 ^+^ a2, b1 ^+^ b2) +-- | Vector-space instance for tuples. instance (Groundfield a ~ Groundfield b, VectorSpace a, VectorSpace b) => VectorSpace (a, b) where     (a, b) ^/ x = (a ^/ x, b ^/ x) +-- | Inner Product Space instance for tuples. instance (Groundfield a ~ Groundfield b, InnerProductSpace a, InnerProductSpace b) => InnerProductSpace (a, b) where     (a1, b1) `dot` (a2, b2) = (a1 `dot` a2) + (b1 `dot` b2) @@ -41,6 +43,7 @@  -} +-- | R-module instance for tuples with 3 elements. instance Num a => RModule (a,a,a) where     type Groundring (a,a,a) = a     zeroVector = (0,0,0)@@ -49,14 +52,16 @@     (x1,y1,z1) ^+^ (x2,y2,z2) = (x1+x2, y1+y2, z1+z2)     (x1,y1,z1) ^-^ (x2,y2,z2) = (x1-x2, y1-y2, z1-z2) +-- | Vector-space instance for tuples with 3 elements. instance Fractional a => VectorSpace (a,a,a) where     (x,y,z) ^/ a = (x / a, y / a, z / a) -+-- | Inner Product Space instance for tuples with 3 elements. instance Num a => InnerProductSpace (a,a,a) where     (x1,y1,z1) `dot` (x2,y2,z2) = x1 * x2 + y1 * y2 + z1 * z2  +-- | R-module instance for tuples with 4 elements. instance Num a => RModule (a,a,a,a) where     type Groundring (a,a,a,a) = a     zeroVector = (0,0,0,0)@@ -65,14 +70,16 @@     (x1,y1,z1,u1) ^+^ (x2,y2,z2,u2) = (x1+x2, y1+y2, z1+z2, u1+u2)     (x1,y1,z1,u1) ^-^ (x2,y2,z2,u2) = (x1-x2, y1-y2, z1-z2, u1-u2) +-- | Vector-space instance for tuples with 4 elements. instance Fractional a => VectorSpace (a,a,a,a) where     (x,y,z,u) ^/ a = (x / a, y / a, z / a, u / a) -+-- | Inner Product Space instance for tuples with 4 elements. instance Num a => InnerProductSpace (a,a,a,a) where     (x1,y1,z1,u1) `dot` (x2,y2,z2,u2) = x1 * x2 + y1 * y2 + z1 * z2 + u1 * u2  +-- | R-module instance for tuples with 5 elements. instance Num a => RModule (a,a,a,a,a) where     type Groundring (a,a,a,a,a) = a     zeroVector = (0,0,0,0,0)@@ -81,10 +88,11 @@     (x1,y1,z1,u1,v1) ^+^ (x2,y2,z2,u2,v2) = (x1+x2, y1+y2, z1+z2, u1+u2, v1+v2)     (x1,y1,z1,u1,v1) ^-^ (x2,y2,z2,u2,v2) = (x1-x2, y1-y2, z1-z2, u1-u2, v1-v2) +-- | Vector-space instance for tuples with 5 elements. instance Fractional a => VectorSpace (a,a,a,a,a) where     (x,y,z,u,v) ^/ a = (x / a, y / a, z / a, u / a, v / a) -+-- | Inner Product Space instance for tuples with 5 elements. instance Num a => InnerProductSpace (a,a,a,a,a) where     (x1,y1,z1,u1,v1) `dot` (x2,y2,z2,u2,v2) =         x1 * x2 + y1 * y2 + z1 * z2 + u1 * u2 + v1 * v2