packages feed

dunai 0.8.2 → 0.8.3

raw patch · 24 files changed

+484/−414 lines, 24 filesdep +voidPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: void

API changes (from Hackage documentation)

- Control.Monad.Trans.MSF.Except: data Empty
- Control.Monad.Trans.MSF.Except: safely :: Monad m => MSFExcept m a b Empty -> MSF m a b
+ Control.Monad.Trans.MSF.Except: safely :: Monad m => MSFExcept m a b Void -> MSF m a b

Files

CHANGELOG view
@@ -1,3 +1,18 @@+2022-06-21 Ivan Perez <ivan.perez@keera.co.uk>+        * dunai.cabal: Version bump (0.8.3) (#302).+        * src/: Simplify implementation of switch (#276), remove redundant+          imports (#281), remove redundant pragma (#282), use external+          Void type (#79), remove redundant imports (#283), disable warning+          pertaining to orphan instances (#284), style fixes (partial) (#285),+          fix missing re-export of Control.Arrow (#286), further style fixes+          (partial) (#287), avoid name shadowing (#291), remove outdated+          comments (#289), remove unused pragmas (#290), remove unnecessary+          comment (#293), reimplement function without TupleSections (#293),+          standardize haddock comment (#294), add missing documentation (#288),+          disable warning due to use of ListT (#297), fix oudated comment+          (#299), horizontal alignment style changes (#301).+        * README.md: Re-structure README (#300).+ 2022-04-21 Ivan Perez <ivan.perez@keera.co.uk>         * dunai.cabal: Version bump (0.8.2) (#280), syntax rules (#271),           declare CHANGELOG (#273), declare subdir of source-repository (#272).
dunai.cabal view
@@ -30,7 +30,7 @@ build-type:    Simple  name:          dunai-version:       0.8.2+version:       0.8.3 author:        Ivan Perez, Manuel Bärenz maintainer:    ivan.perez@keera.co.uk homepage:      https://github.com/ivanperez-keera/dunai@@ -140,7 +140,8 @@    if impl(ghc <= 7.8.4)     build-depends:-      transformers-compat+        transformers-compat+      , void   test-suite hlint
src/Control/Arrow/Util.hs view
@@ -6,15 +6,16 @@ -- Utility functions to work with 'Arrow's. module Control.Arrow.Util where -import Control.Arrow+-- External imports+import Control.Arrow (Arrow, arr, (&&&), (>>^), (^<<))  -- | Constantly produce the same output. constantly :: Arrow a => b -> a c b constantly = arr . const {-# INLINE constantly #-} --- * 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 = (^<<)
src/Control/Monad/Trans/MSF.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE Rank2Types #-} -- | -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016 -- License    : BSD3@@ -16,6 +15,7 @@     )   where +-- Internal imports import Control.Monad.Trans.MSF.Except import Control.Monad.Trans.MSF.Maybe import Control.Monad.Trans.MSF.Random
src/Control/Monad/Trans/MSF/Except.hs view
@@ -1,7 +1,6 @@-{-# LANGUAGE Arrows        #-}-{-# LANGUAGE CPP           #-}-{-# LANGUAGE Rank2Types    #-}-{-# LANGUAGE TupleSections #-}+{-# LANGUAGE Arrows     #-}+{-# LANGUAGE CPP        #-}+{-# LANGUAGE Rank2Types #-} -- | -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016 -- License    : BSD3@@ -12,22 +11,30 @@ -- 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+    ( module Control.Monad.Trans.MSF.Except+    , module Control.Monad.Trans.Except+    )+  where --- External-import           Control.Applicative+-- External imports+#if !MIN_VERSION_base(4,8,0)+import           Control.Applicative        (Applicative (..), (<$>))+#endif++import           Control.Arrow              (arr, returnA, (<<<), (>>>)) import qualified Control.Category           as Category import           Control.Monad              (ap, liftM)-import           Control.Monad.Trans.Class+import           Control.Monad.Trans.Class  (lift) import           Control.Monad.Trans.Except hiding (liftCallCC, liftListen,                                              liftPass)-import           Control.Monad.Trans.Maybe+import           Control.Monad.Trans.Maybe  (MaybeT, runMaybeT)+import           Data.Void                  (Void) --- Internal-import Data.MonadicStreamFunction-import Data.MonadicStreamFunction.InternalCore+-- Internal imports+import Data.MonadicStreamFunction              (arrM, constM, count, feedback,+                                                liftTransS, mapMaybeS, morphS,+                                                reactimate)+import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF))  -- External, necessary for older base versions #if __GLASGOW_HASKELL__ < 802@@ -49,8 +56,8 @@   then throwS  -< e   else returnA -< a --- | Variant of 'throwOnCond' for Kleisli arrows.--- | Throws the exception when the input is 'True'.+-- | Throws the exception when the input is 'True'. Variant of 'throwOnCond'+-- for Kleisli arrows. throwOnCondM :: Monad m => (a -> m Bool) -> e -> MSF (ExceptT e m) a a throwOnCondM cond e = proc a -> do   b <- arrM (lift . cond) -< a@@ -68,8 +75,8 @@   then throwS  -< e   else returnA -< () --- | When the input is @Just e@, throw the exception @e@.---   (Does not output any actual data.)+-- | 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 throwS @@ -85,78 +92,74 @@ pass :: Monad m => MSF (ExceptT e m) a a pass = Category.id --- | Converts an 'MSF' in 'MaybeT' to an 'MSF' in 'ExceptT'.---   Whenever 'Nothing' is thrown, throw @()@ instead.+-- | Converts an 'MSF' in 'MaybeT' to an 'MSF' in 'ExceptT'. Whenever+-- 'Nothing' is thrown, throw @()@ instead. maybeToExceptS :: (Functor m, Monad m)                => MSF (MaybeT m) a b -> MSF (ExceptT () m) a b maybeToExceptS = morphS (ExceptT . (maybe (Left ()) Right <$>) . runMaybeT)  -- * Catching exceptions --- | 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.+-- | 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 = safely $ do   e <- try msf   safe $ f e  -- | Similar to Yampa's delayed switching. Loses a @b@ in case of an exception.-untilE :: Monad m => MSF m a b -> MSF m b (Maybe e)+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  <- liftTransS msf  -< a   me <- liftTransS msfe -< b   inExceptT -< ExceptT $ return $ maybe (Right b) Left me --- TODO This needs to be renamed as 'runExceptS'!--- 'exceptS' would have type @MSF m a (Either e b) -> MSF (ExceptT e m) a b@ -- | 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.+-- If an exception occurs, the current 'MSF' continuation is tested again on+-- the next input. exceptS :: (Functor m, Monad m) => MSF (ExceptT e m) a b -> MSF m a (Either e b) exceptS = transG return $ const $ fmap f . runExceptT   where     f (Left e)       = (Left e , Nothing)     f (Right (b, c)) = (Right b, Just c ) --- | 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.+-- | 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 --- | In case an exception occurs in the first argument,---   replace the exception by the second component of the tuple.+-- | 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 = runMSFExcept $ do   _       <- try $ msf <<< arr fst   (_, e2) <- currentInput   return e2 - -- * Monad interface for Exception MSFs --- | 'MSF's with an 'ExceptT' transformer layer---   are in fact monads /in the exception type/.+-- | '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.+--   * '>>=' 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. --   * @m@: The monad that the 'MSF' may take side effects in. --   * @a@: The input type --   * @b@: The output type --   * @e@: The type of exceptions that can be thrown 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.+-- | Execute an 'MSF' in 'ExceptT' until it raises an exception.+--+-- An alias for the 'MSFExcept' constructor, used to enter the 'MSFExcept'+-- monad context. try :: MSF (ExceptT e m) a b -> MSFExcept m a b e try = MSFExcept @@ -183,40 +186,34 @@  -- | Execute an MSF and, if it throws an exception, recover by switing to a -- second MSF.-handleExceptT-  :: Monad m-  => MSF (ExceptT e1 m) a b-  -> (e1 -> MSF (ExceptT e2 m) a b)-  -> MSF (ExceptT e2 m) a b+handleExceptT :: Monad m+              => MSF (ExceptT e1 m) a b+              -> (e1 -> MSF (ExceptT e2 m) a b)+              -> MSF (ExceptT e2 m) a b handleExceptT msf f = flip handleGen msf $ \a mbcont -> do   ebcont <- lift $ runExceptT mbcont   case ebcont of     Left e          -> unMSF (f e) a     Right (b, msf') -> return (b, handleExceptT 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+-- | If no exception can occur, the 'MSF' can be executed without the 'ExceptT'+-- layer.+safely :: Monad m => MSFExcept m a b Void -> MSF m a b safely (MSFExcept msf) = morphS fromExcept msf   where-    -- We can assume that the pattern @Left e@ will not occur,-    -- since @e@ would have to be of type @Empty@.+    -- We can assume that the pattern @Left e@ will not occur, since @e@ would+    -- have to be of type @Void@.     fromExcept ma = do       rightMa <- runExceptT ma       return $ fromRight (error "safely: Received `Left`") rightMa --- | An 'MSF' without an 'ExceptT' layer never throws an exception,---   and can thus have an arbitrary exception type.+-- | 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 . liftTransS  -- | 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.+-- 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 @@ -224,8 +221,8 @@ once_ :: Monad m => m e -> MSFExcept m a b e once_ = once . const --- | Advances a single tick with the given Kleisli arrow,---   and then throws an exception.+-- | Advances a single tick with the given Kleisli arrow, and then throws an+-- exception. step :: Monad m => (a -> m (b, e)) -> MSFExcept m a b e step f = try $ proc a -> do   n      <- count           -< ()@@ -233,29 +230,22 @@   _      <- throwOn'        -< (n > (1 :: Int), e)   returnA                   -< b --- | Advances a single tick outputting the value,---   and then throws '()'.+-- | Advances a single tick outputting the value, and then throws '()'. step_ :: Monad m => b -> MSFExcept m a b ()-step_ = step . const . return . (, ())+step_ b = step $ const $ return (b, ()) --- | Converts a list to an 'MSFExcept',---   which outputs an element of the list at each step,---   throwing '()' when the list ends.+-- | Converts a list to an 'MSFExcept', which outputs an element of the list at+-- each step, throwing '()' when the list ends. listToMSFExcept :: Monad m => [b] -> MSFExcept m a b () listToMSFExcept = mapM_ step_  -- * Utilities definable in terms of 'MSFExcept' --- TODO This is possibly not the best location for these functions,--- but moving them to Data.MonadicStreamFunction.Util would form an import cycle--- that could only be broken by moving a few things to Data.MonadicStreamFunction.Core--- (that probably belong there anyways).- -- | Extract an 'MSF' from a monadic action. ----- Runs a monadic action that produces an 'MSF' on the first iteration/step, and--- uses that 'MSF' as the main signal function for all inputs (including the--- first one).+-- Runs a monadic action that produces an 'MSF' on the first iteration/step,+-- and uses that 'MSF' as the main signal function for all inputs (including+-- the first one). performOnFirstSample :: Monad m => m (MSF m a b) -> MSF m a b performOnFirstSample sfaction = safely $ do   msf <- once_ sfaction@@ -274,19 +264,24 @@ -- | Run first MSF until the second value in the output tuple is @Just c@ (for -- some @c@), then start the second MSF. ----- Analog to Yampa's [@switch@](https://hackage.haskell.org/package/Yampa/docs/FRP-Yampa-Switches.html#v:switch),+-- Analog to Yampa's+-- [@switch@](https://hackage.haskell.org/package/Yampa/docs/FRP-Yampa-Switches.html#v:switch), -- with 'Maybe' instead of @Event@. switch :: Monad m => MSF m a (b, Maybe c) -> (c -> MSF m a b) -> MSF m a b-switch sf f = catchS ef  f+switch sf f = catchS ef f   where+    -- Run sf, throwing an exception if there is a no-Nothing value in the+    -- second element of the pair, and returning the first element otherwise.     ef = proc a -> do-           (b,me)  <- liftTransS sf -< a-           inExceptT -< ExceptT $ return $ maybe (Right b) Left me+           (b, me)  <- liftTransS sf  -< a+           throwMaybe                 -< me+           returnA                    -< b  -- | Run first MSF until the second value in the output tuple is @Just c@ (for -- some @c@), then start the second MSF. ----- Analog to Yampa's [@dswitch@](https://hackage.haskell.org/package/Yampa/docs/FRP-Yampa-Switches.html#v:dSwitch),+-- Analog to Yampa's+-- [@dswitch@](https://hackage.haskell.org/package/Yampa/docs/FRP-Yampa-Switches.html#v:dSwitch), -- with 'Maybe' instead of @Event@. dSwitch :: Monad m => MSF m a (b, Maybe c) -> (c -> MSF m a b) -> MSF m a b dSwitch sf f = catchS ef f@@ -305,11 +300,14 @@        -> MSF m1 a1 b1        -> MSF m2 a2 b2 transG transformInput transformOutput msf = go-  where go = MSF $ \a2 -> do-               (b2, msf') <- transformOutput a2 $ unMSF msf =<< transformInput a2-               case msf' of-                 Just msf'' -> return (b2, transG transformInput transformOutput msf'')-                 Nothing    -> return (b2, go)+  where+    go = MSF $ \a2 -> do+           (b2, msf') <- transformOutput a2 $ unMSF msf =<< transformInput a2+           case msf' of+             Just msf'' ->+               return (b2, transG transformInput transformOutput msf'')+             Nothing ->+               return (b2, go)  -- | Use a generic handler to handle exceptions in MSF processing actions. handleGen :: (a -> m1 (b1, MSF m1 a b1) -> m2 (b2, MSF m2 a b2))
src/Control/Monad/Trans/MSF/List.hs view
@@ -1,42 +1,71 @@ {-# LANGUAGE CPP #-}+-- The following warning id disabled so that we do not see warnings during+-- compilation caused by the intentional use of ListT.+#if __GLASGOW_HASKELL__ < 800+{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}+#else+{-# OPTIONS_GHC -Wno-deprecations #-}+#endif -- | -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016 -- License    : BSD3 -- Maintainer : ivan.perez@keera.co.uk+--+-- 'MSF's with a list monadic layer.+--+-- This module contains functions to work with MSFs that include a 'ListT'+-- monadic layer. MSFs on a list monad may produce multiple outputs and+-- continuations, or none. This enables the possibility for spawning new MSFs,+-- or stopping MSFs, at will.+--+-- A common use case is to be able to dynamically spawn new interactive+-- elements in applications (e.g., a game object that splits in two, or that+-- fires to an enemy).+--+-- WARNING: the ListT transformer is considered dangerous, and imposes+-- additional constraints on the inner monad in order for the combination of+-- the monad and the transformer to be a monad. Use at your own risk. module Control.Monad.Trans.MSF.List-  ( module Control.Monad.Trans.MSF.List-  , module Control.Monad.Trans.List-  ) where+    {-# WARNING "This module uses the ListT transformer, which is considered deprecated." #-}+    ( module Control.Monad.Trans.MSF.List+    , module Control.Monad.Trans.List+    )+  where --- External+-- External imports #if !MIN_VERSION_base(4,8,0) import Control.Applicative ((<$>)) #endif  import Control.Monad.Trans.List hiding (liftCallCC, liftCatch) --- Internal-import Data.MonadicStreamFunction+-- Internal imports import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF))  -- * List monad --- Name alternative (in the article): collect+-- | Run an 'MSF' in the 'ListT' transformer (i.e., multiple MSFs producing+-- each producing one output), by applying the input stream to each MSF in the+-- list transformer and concatenating the outputs of the MSFs together.+--+-- An MSF in the ListT transformer can spawn into more than one MSF, or none,+-- so the outputs produced at each individual step are not guaranteed to all+-- have the same length. widthFirst :: (Functor m, Monad m) => MSF (ListT m) a b -> MSF m a [b]-widthFirst msf = widthFirst' [msf] where+widthFirst msf = widthFirst' [msf]+  where     widthFirst' msfs = MSF $ \a -> do-        (bs, msfs') <- unzip . concat <$> mapM (runListT . flip unMSF a) msfs-        return (bs, widthFirst' msfs')-+      (bs, msfs') <- unzip . concat <$> mapM (runListT . flip unMSF a) msfs+      return (bs, widthFirst' msfs') --- Name alternatives: "choose", "parallely" (problematic because it's not multicore)+-- | Build an 'MSF' in the 'ListT' transformer by broadcasting the input stream+-- value to each MSF in a given list. sequenceS :: Monad m => [MSF m a b] -> MSF (ListT m) a b sequenceS msfs = MSF $ \a -> ListT $ sequence $ apply a <$> msfs   where     apply a msf = do-        (b, msf') <- unMSF msf a-        return (b, sequenceS [msf'])--- sequenceS = foldl (<+>) arrowzero . map liftMSFTrans+      (b, msf') <- unMSF msf a+      return (b, sequenceS [msf'])  -- | Apply an 'MSF' to every input. mapMSF :: Monad m => MSF m a b -> MSF m [a] [b]
src/Control/Monad/Trans/MSF/Maybe.hs view
@@ -1,5 +1,4 @@-{-# LANGUAGE Arrows     #-}-{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE Arrows #-} -- | -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016 -- License    : BSD3@@ -9,18 +8,23 @@ -- 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-  , maybeToExceptS-  ) where+    ( module Control.Monad.Trans.MSF.Maybe+    , module Control.Monad.Trans.Maybe+    , maybeToExceptS+    )+  where --- External+-- External imports+import Control.Arrow             (returnA, (>>>), arr) import Control.Monad.Trans.Maybe hiding (liftCallCC, liftCatch, liftListen,                                   liftPass) --- Internal-import Control.Monad.Trans.MSF.Except-import Data.MonadicStreamFunction+-- Internal imports+import Control.Monad.Trans.MSF.Except (ExceptT, exceptS, listToMSFExcept,+                                       maybeToExceptS, reactimateExcept,+                                       runExceptT, runMSFExcept, safe, safely,+                                       try)+import Data.MonadicStreamFunction     (MSF, arrM, constM, liftTransS, morphS)  -- * Throwing 'Nothing' as an exception ("exiting") @@ -48,20 +52,22 @@ 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.+-- | 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 <- liftTransS msf  -< a   c <- liftTransS 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-  :: (Functor m, Monad m)-  => MSF (MaybeT m) a b -> MSF m a b -> MSF m a b+-- | When an exception occurs in the first 'msf', the second 'msf' is executed+-- from there.+catchMaybe :: (Functor m, Monad m)+           => MSF (MaybeT m) a b+           -> MSF m a b+           -> MSF m a b catchMaybe msf1 msf2 = safely $ do   _ <- try $ maybeToExceptS msf1   safe msf2@@ -69,33 +75,35 @@ -- * Converting to and from 'MaybeT'  -- | Convert exceptions into `Nothing`, discarding the exception value.-exceptToMaybeS :: (Functor m, Monad m) => MSF (ExceptT e m) a b -> MSF (MaybeT m) a b-exceptToMaybeS = morphS $ MaybeT . fmap (either (const Nothing) Just) . runExceptT+exceptToMaybeS :: (Functor m, Monad m)+               => MSF (ExceptT e m) a b+               -> MSF (MaybeT m) a b+exceptToMaybeS =+  morphS $ MaybeT . fmap (either (const Nothing) Just) . runExceptT --- | Converts a list to an 'MSF' in 'MaybeT',---   which outputs an element of the list at each step,---   throwing 'Nothing' when the list ends.+-- | Converts a list to an 'MSF' in 'MaybeT', which outputs an element of the+-- list at each step, throwing 'Nothing' when the list ends. listToMaybeS :: (Functor m, Monad m) => [b] -> MSF (MaybeT m) a b listToMaybeS = exceptToMaybeS . runMSFExcept . listToMSFExcept  -- * 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.++-- | 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 :: (Functor m, Monad m) => MSF (MaybeT m) a b -> MSF m a (Maybe b) runMaybeS msf = exceptS (maybeToExceptS msf) >>> arr eitherToMaybe   where     eitherToMaybe (Left ()) = Nothing     eitherToMaybe (Right b) = Just b - -- | Reactimates an 'MSF' in the 'MaybeT' monad until it throws 'Nothing'.-reactimateMaybe-  :: (Functor m, Monad m)-  => MSF (MaybeT m) () () -> m ()+reactimateMaybe :: (Functor m, Monad m)+                => MSF (MaybeT m) () ()+                -> m () reactimateMaybe msf = reactimateExcept $ try $ maybeToExceptS msf  -- | Run an 'MSF' fed from a list, discarding results. Useful when one needs to -- combine effects and streams (i.e., for testing purposes). embed_ :: (Functor m, Monad m) => MSF m a () -> [a] -> m ()- embed_ msf as = reactimateMaybe $ listToMaybeS as >>> liftTransS msf
src/Control/Monad/Trans/MSF/RWS.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} -- | -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016 -- License    : BSD3@@ -11,20 +12,23 @@ -- has to be included, i.e. 'Control.Monad.RWS.Strict' instead of -- 'Control.Monad.RWS' or 'Control.Monad.RWS.Lazy'. module Control.Monad.Trans.MSF.RWS-  ( module Control.Monad.Trans.MSF.RWS-  , module Control.Monad.Trans.RWS.Strict-  ) where+    ( module Control.Monad.Trans.MSF.RWS+    , module Control.Monad.Trans.RWS.Strict+    )+  where --- External+-- External imports import Control.Monad.Trans.RWS.Strict hiding (liftCallCC, liftCatch)-import Data.Functor                   ((<$>))-import Data.Monoid --- Internal-import Data.MonadicStreamFunction+#if !MIN_VERSION_base(4,8,0)+import Data.Functor ((<$>))+import Data.Monoid  (Monoid)+#endif --- * 'RWS' (Reader-Writer-State) monad+-- Internal imports+import Data.MonadicStreamFunction (MSF, morphGS) +-- * 'RWS' (Reader-Writer-State) monad  -- | Wrap an 'MSF' with explicit state variables in 'RWST' monad. rwsS :: (Functor m, Monad m, Monoid w)
src/Control/Monad/Trans/MSF/Random.hs view
@@ -11,38 +11,37 @@ -- Under the hood, 'RandT' is basically just 'StateT', with the current random -- number generator as mutable state. module Control.Monad.Trans.MSF.Random-  (-    runRandS-  , evalRandS--  , getRandomS-  , getRandomsS-  , getRandomRS-  , getRandomRS_-  , getRandomsRS-  , getRandomsRS_-  ) where+    ( runRandS+    , evalRandS+    , getRandomS+    , getRandomsS+    , getRandomRS+    , getRandomRS_+    , getRandomsRS+    , getRandomsRS_+    )+  where --- External-import Control.Monad.Random+-- External imports+import Control.Arrow        (arr, (>>>))+import Control.Monad.Random (MonadRandom, RandT, Random, RandomGen, getRandom,+                             getRandomR, getRandomRs, getRandoms, runRandT) --- Internal-import Control.Monad.Trans.MSF.State-import Data.MonadicStreamFunction+-- Internal imports+import Control.Monad.Trans.MSF.State (StateT (..), runStateS_)+import Data.MonadicStreamFunction    (MSF, arrM, constM, morphS) --- | Run an 'MSF' in the 'RandT' random number monad transformer---   by supplying an initial random generator.---   Updates the generator every step.+-- | Run an 'MSF' in the 'RandT' random number monad transformer by supplying+-- an initial random generator. Updates the generator every step. runRandS :: (RandomGen g, Functor m, Monad m)          => MSF (RandT g m) a b          -> g -- ^ The initial random number generator.          -> MSF m a (g, b) runRandS = runStateS_ . morphS (StateT . runRandT) --- | Evaluate an 'MSF' in the 'RandT' transformer,---   i.e. extract possibly random values---   by supplying an initial random generator.---   Updates the generator every step but discharges the generator.+-- | Evaluate an 'MSF' in the 'RandT' transformer, i.e. extract possibly random+-- values by supplying an initial random generator. Updates the generator every+-- step but discharges the generator. evalRandS :: (RandomGen g, Functor m, Monad m)           => MSF (RandT g m) a b -> g -> MSF m a b evalRandS msf g = runRandS msf g >>> arr snd@@ -51,7 +50,6 @@ getRandomS :: (MonadRandom m, Random b) => MSF m a b getRandomS = constM getRandom - -- | Create a stream of lists of random values. getRandomsS :: (MonadRandom m, Random b) => MSF m a [b] getRandomsS = constM getRandoms@@ -60,8 +58,8 @@ getRandomRS :: (MonadRandom m, Random b) => (b, b) -> MSF m a b getRandomRS range = constM $ getRandomR range --- | Create a stream of random values in a given range,---   where the range is specified on every tick.+-- | Create a stream of random values in a given range, where the range is+-- specified on every tick. getRandomRS_ :: (MonadRandom m, Random b) => MSF m (b, b) b getRandomRS_  = arrM getRandomR @@ -69,7 +67,7 @@ getRandomsRS :: (MonadRandom m, Random b) => (b, b) -> MSF m a [b] getRandomsRS range = constM $ getRandomRs range --- | Create a stream of lists of random values in a given range,---   where the range is specified on every tick.+-- | Create a stream of lists of random values in a given range, where the+-- range is specified on every tick. getRandomsRS_ :: (MonadRandom m, Random b) => MSF m (b, b) [b] getRandomsRS_ = arrM getRandomRs
src/Control/Monad/Trans/MSF/Reader.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE Rank2Types #-} -- | -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016 -- License    : BSD3@@ -11,18 +10,20 @@ -- 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.Reader-  -- * 'Reader' 'MSF' running and wrapping.-  , readerS-  , runReaderS-  , runReaderS_-  ) where+    ( module Control.Monad.Trans.Reader+    -- * 'Reader' 'MSF' running and wrapping.+    , readerS+    , runReaderS+    , runReaderS_+    )+  where --- External+-- External imports+import Control.Arrow              (arr, (>>>)) import Control.Monad.Trans.Reader hiding (liftCallCC, liftCatch) --- Internal-import Data.MonadicStreamFunction+-- Internal imports+import Data.MonadicStreamFunction (MSF, morphGS)  -- * Reader 'MSF' running and wrapping @@ -36,8 +37,7 @@ runReaderS :: Monad m => MSF (ReaderT r m) a b -> MSF m (r, a) b runReaderS = morphGS $ \f (r, a) -> runReaderT (f a) r - -- | Build an 'MSF' /function/ that takes a fixed environment as additional -- input, from an MSF in the 'Reader' monad. runReaderS_ :: Monad m => MSF (ReaderT s m) a b -> s -> MSF m a b-runReaderS_ msf s = arr (\a -> (s,a)) >>> runReaderS msf+runReaderS_ msf s = arr (\a -> (s, a)) >>> runReaderS msf
src/Control/Monad/Trans/MSF/State.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE CPP #-} -- | -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016 -- License    : BSD3@@ -16,23 +16,27 @@ -- the strict version has to be included, i.e. 'Control.Monad.State.Strict' -- instead of 'Control.Monad.State' or 'Control.Monad.State.Lazy'. module Control.Monad.Trans.MSF.State-  ( module Control.Monad.Trans.State.Strict-  -- * 'State' 'MSF' running and wrapping-  , stateS-  , runStateS-  , runStateS_-  , runStateS__-  ) where+    ( module Control.Monad.Trans.State.Strict+    -- * 'State' 'MSF' running and wrapping+    , stateS+    , runStateS+    , runStateS_+    , runStateS__+    )+  where --- External-import Control.Applicative+-- External imports+#if !MIN_VERSION_base(4,8,0)+import Control.Applicative ((<$>))+#endif++import Control.Arrow                    (arr, (>>>)) import Control.Monad.Trans.State.Strict hiding (liftCallCC, liftCatch,                                          liftListen, liftPass) import Data.Tuple                       (swap) --- Internal-import Data.MonadicStreamFunction.Core-import Data.MonadicStreamFunction.InternalCore+-- Internal imports+import Data.MonadicStreamFunction.Core (MSF, morphGS, feedback)  -- * 'State' 'MSF' running and wrapping @@ -51,12 +55,15 @@ -- | 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.-runStateS_ :: (Functor m, Monad m) => MSF (StateT s m) a b -> s -> MSF m a (s, b)-runStateS_ msf s = feedback s-                 $ arr swap >>> runStateS msf >>> arr (\(s', b) -> ((s', b), s'))+runStateS_ :: (Functor m, Monad m)+           => MSF (StateT s m) a b+           -> s+           -> MSF m a (s, b)+runStateS_ msf s =+  feedback s $+    arr swap >>> runStateS msf >>> arr (\(s', b) -> ((s', b), s')) --- TODO Rename this to execStateS!--- | Build an 'MSF' /function/ that takes a fixed state as additional--- input, from an 'MSF' in the 'State' monad.+-- | Build an 'MSF' /function/ that takes a fixed state as additional input,+-- from an 'MSF' in the 'State' monad. runStateS__ :: (Functor m, Monad m) => MSF (StateT s m) a b -> s -> MSF m a b runStateS__ msf s = runStateS_ msf s >>> arr snd
src/Control/Monad/Trans/MSF/Writer.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} -- | -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016 -- License    : BSD3@@ -15,19 +16,23 @@ -- the strict version has to be included, i.e. 'Control.Monad.Writer.Strict' -- instead of 'Control.Monad.Writer' or 'Control.Monad.Writer.Lazy'. module Control.Monad.Trans.MSF.Writer-  ( module Control.Monad.Trans.Writer.Strict-  -- * 'Writer' 'MSF' running and wrapping-  , writerS-  , runWriterS-  ) where+    ( module Control.Monad.Trans.Writer.Strict+    -- * 'Writer' 'MSF' running and wrapping+    , writerS+    , runWriterS+    )+  where --- External+-- External imports import Control.Monad.Trans.Writer.Strict hiding (liftCallCC, liftCatch, pass)-import Data.Functor                      ((<$>))-import Data.Monoid --- Internal-import Data.MonadicStreamFunction+#if !MIN_VERSION_base(4,8,0)+import Data.Functor ((<$>))+import Data.Monoid  (Monoid)+#endif++-- Internal imports+import Data.MonadicStreamFunction (MSF, morphGS)  -- * 'Writer' 'MSF' running and wrapping 
src/Data/MonadicStreamFunction.hs view
@@ -47,14 +47,14 @@   )  where --- External+-- External imports import Control.Arrow --- Internal+-- Internal imports import Data.MonadicStreamFunction.Core import Data.MonadicStreamFunction.Util --- Internal (Instances)+-- Internal imports (instances) import Data.MonadicStreamFunction.Instances.ArrowChoice () import Data.MonadicStreamFunction.Instances.ArrowLoop   () import Data.MonadicStreamFunction.Instances.ArrowPlus   ()
src/Data/MonadicStreamFunction/Async.hs view
@@ -7,9 +7,8 @@ -- i.e. that change the speed at which data enters or leaves the 'MSF'. module Data.MonadicStreamFunction.Async where --- Internal-import Data.MonadicStreamFunction.Core-import Data.MonadicStreamFunction.InternalCore+-- Internal imports+import Data.MonadicStreamFunction.InternalCore (MSF(MSF, unMSF)) import Data.MonadicStreamFunction.Util         (MStream)  -- |@@ -21,7 +20,7 @@ -- >>> let intstream = constS $ putStrLn "Enter a list of Ints:" >> readLn :: MStream IO [Int] -- >>> reactimate $ concatS intstream >>> arrM print -- Enter a list of Ints:--- [1,2,33]+-- [1, 2, 33] -- 1 -- 2 -- 33@@ -30,14 +29,14 @@ -- Enter a list of Ints: -- [] -- Enter a list of Ints:--- [1,2]+-- [1, 2] -- 1 -- 2 -- Enter a list of Ints: -- ... ----- Beware that @concatS msf@ becomes unproductive when @msf@ starts outputting empty lists forever.--- This is ok:+-- Beware that @concatS msf@ becomes unproductive when @msf@ starts outputting+-- empty lists forever. This is ok: -- -- >>> let boolToList b = if b then ["Yes"] else [] -- >>> let everyOddEmpty = count >>> arr (even >>> boolToList)@@ -64,6 +63,3 @@     tick msf' []     = do       (bs, msf'') <- unMSF msf' ()       tick msf'' bs--- TODO Maybe this can be written more nicely with exceptions?--- Similarly takeS :: Int -> MSF m a b -> MSFExcept m a b () throws an exception after n ticks--- Or with merge?
src/Data/MonadicStreamFunction/Core.hs view
@@ -1,4 +1,10 @@+{-# LANGUAGE CPP        #-} {-# LANGUAGE Rank2Types #-}+-- We disable the following warning because this module purposefully defines+-- orphan instances. This is a design decision in Dunai, so that we give+-- implementors further flexibility while giving most users the features they+-- expect.+{-# OPTIONS_GHC -fno-warn-orphans #-} -- | -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016 -- License    : BSD3@@ -56,51 +62,53 @@     -- * Simulation   , reactimate   , embed-  , module Control.Arrow+  , module X   )   where -import Control.Applicative-import Control.Arrow-import Control.Category          as C-import Control.Monad.Base-import Control.Monad.Trans.Class-import Data.Tuple                (swap)-import Prelude                   hiding (id, sum, (.))+-- External imports+import           Control.Arrow             (Arrow (..), (>>>))+import qualified Control.Arrow             as X+import           Control.Category          as C (id, (.))+import           Control.Monad.Base        (MonadBase, liftBase)+import           Control.Monad.Trans.Class (MonadTrans, lift)+import           Prelude                   hiding (id, sum, (.)) -import Data.MonadicStreamFunction.InternalCore (MSF, embed, feedback, morphGS, reactimate)+#if !MIN_VERSION_base(4,8,0)+import Control.Applicative (Applicative(..))+#endif +-- Internal imports+import Data.MonadicStreamFunction.InternalCore (MSF, embed, feedback, morphGS,+                                                reactimate)+ -- * Definitions  -- | 'Arrow' instance for 'MSF's. instance Monad m => Arrow (MSF m) where-   arr f = arrM (return . f) -  -- first sf = MSF $ \(a,c) -> do-  --   (b, sf') <- unMSF sf a-  --   b `seq` return ((b, c), first sf')--  first = morphGS $ \f (a,c) -> do-            (b, msf') <- f a-            return ((b, c), msf')-+  first =+    -- This implementation is equivalent to:+    -- first sf = MSF $ \(a, c) -> do+    --   (b, sf') <- unMSF sf a+    --   b `seq` return ((b, c), first sf')+    morphGS $ \f (a, c) -> do+      (b, msf') <- f a+      return ((b, c), msf')  -- * Functor and applicative instances  -- | 'Functor' instance for 'MSF's. instance Monad 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 'MSF's. instance (Functor m, Monad m) => Applicative (MSF m a) where   -- It is possible to define this instance with only Applicative m   pure = arr . const-  fs <*> bs = (fs &&& bs) >>> arr (uncurry ($)) +  fs <*> bs = (fs &&& bs) >>> arr (uncurry ($))  -- ** Lifting point-wise computations @@ -112,11 +120,14 @@ -- -- Generalisation of 'arr' from 'Arrow' to monadic functions. arrM :: Monad m => (a -> m b) -> MSF m a b---arrM f = go---  where go = MSF $ \a -> do---               b <- f a---               return (b, go)-arrM f = morphGS (\i a -> i a >>= \(_,c) -> f a >>= \b -> return (b, c)) C.id+arrM f =+  -- This implementation is equivalent to:+  -- arrM f = go+  --   where+  --     go = MSF $ \a -> do+  --            b <- f a+  --            return (b, go)+  morphGS (\i a -> i a >>= \(_, c) -> f a >>= \b -> return (b, c)) C.id  -- | Monadic lifting from one monad into another liftBaseM :: (Monad m2, MonadBase m1 m2) => (a -> m1 b) -> MSF m2 a b@@ -130,6 +141,7 @@ liftBaseS = morphS liftBase  -- *** MonadBase+ -- | 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 = liftBaseS sf1 >>> sf2@@ -143,7 +155,6 @@ -- *** MonadTrans  -- | Lift inner monadic actions in monad stacks.- liftTransS :: (MonadTrans t, Monad m, Monad (t m))            => MSF m a b            -> MSF (t m) a b@@ -156,9 +167,9 @@ -- This is just a convenience function when you have a function to move across -- monads, because the signature of 'morphGS' is a bit complex. morphS :: (Monad m2, Monad m1)-      => (forall c . m1 c -> m2 c)-      -> MSF m1 a b-      -> MSF m2 a b+       => (forall c . m1 c -> m2 c)+       -> MSF m1 a b+       -> MSF m2 a b morphS morph = morphGS morph'   where     -- The following makes the a's and the b's the same, and it just says:@@ -168,10 +179,11 @@     -- Remember that:     -- morphGS :: Monad m2     --         => (forall c . (a1 -> m1 (b1, c)) -> (a2 -> m2 (b2, c)))-    --           -- ^ The natural transformation. @mi@, @ai@ and @bi@ for @i = 1, 2@-    --           --   can be chosen freely, but @c@ must be universally quantified+    --           -- ^ The natural transformation. @mi@, @ai@ and @bi@ for+    --           --   @i = 1, 2@ can be chosen freely, but @c@ must be+    --           --   universally quantified     --         -> MSF m1 a1 b1     --         -> MSF m2 a2 b2     --     --  morph' :: (forall c . (a -> m1 (b, c)) -> (a -> m2 (b, c)))-        morph' m1F = morph . m1F+    morph' m1F = morph . m1F
src/Data/MonadicStreamFunction/Instances/ArrowChoice.hs view
@@ -10,10 +10,12 @@ -- Import this module to include that (orphan) instance. module Data.MonadicStreamFunction.Instances.ArrowChoice where -import Control.Arrow+-- External imports+import Control.Arrow (ArrowChoice (..)) -import Data.MonadicStreamFunction.Core-import Data.MonadicStreamFunction.InternalCore+-- Internal imports+import Data.MonadicStreamFunction.Core         ()+import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF))  -- | 'ArrowChoice' instance for MSFs. instance Monad m => ArrowChoice (MSF m) where
src/Data/MonadicStreamFunction/Instances/ArrowLoop.hs view
@@ -13,17 +13,18 @@ -- This is only defined for monads that are instances of 'MonadFix'. module Data.MonadicStreamFunction.Instances.ArrowLoop where --- External-import Control.Arrow-import Control.Monad.Fix+-- External imports+import Control.Arrow     (ArrowLoop (..))+import Control.Monad.Fix (MonadFix) -import Data.MonadicStreamFunction.Core-import Data.MonadicStreamFunction.InternalCore+-- Internal imports+import Data.MonadicStreamFunction.Core         ()+import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF))  -- | 'ArrowLoop' instance for MSFs. The monad must be an instance of -- 'MonadFix'. instance MonadFix m => ArrowLoop (MSF m) where   loop :: MSF m (b, d) (c, d) -> MSF m b c   loop sf = MSF $ \a -> do-              rec ((b,c), sf') <- unMSF sf (a, c)+              rec ((b, c), sf') <- unMSF sf (a, c)               return (b, loop sf')
src/Data/MonadicStreamFunction/Instances/ArrowPlus.hs view
@@ -11,25 +11,27 @@ -- This is only defined for monads that are instances of 'MonadPlus'. module Data.MonadicStreamFunction.Instances.ArrowPlus where --- base-import Control.Applicative-import Control.Arrow-import Control.Monad+-- External imports+import Control.Applicative (Alternative (..))+import Control.Arrow       (ArrowPlus (..), ArrowZero (..))+import Control.Monad       (MonadPlus, mplus, mzero) --- dunai-import Data.MonadicStreamFunction.Core-import Data.MonadicStreamFunction.InternalCore+-- Internal imports+import Data.MonadicStreamFunction.Core         ()+import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF)) --- | Instance of 'ArrowZero' for Monadic Stream Functions ('MSF').---   The monad must be an instance of 'MonadPlus'.+-- | 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 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 +-- | Instance of 'Alternative' for Monadic Stream Functions ('MSF'),+-- implemented using the 'ArrowZero' and 'ArrowPlus' instances. instance (Functor m, Monad m, MonadPlus m) => Alternative (MSF m a) where   empty = zeroArrow   (<|>) = (<+>)
src/Data/MonadicStreamFunction/Instances/Num.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE TypeFamilies #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -- | -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016@@ -22,12 +21,13 @@ -- msf3 = (msf1 &&& msf2) >>> arr (uncurry (+)) -- @ ----- Instances are provided for the type classes 'Num', 'Fractional'--- and 'Floating'.+-- 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+-- Internal imports+import Control.Arrow.Util              (constantly, elementwise, elementwise2)+import Data.MonadicStreamFunction.Core (MSF)  -- | 'Num' instance for 'MSF's. instance (Monad m, Num b) => Num (MSF m a b) where
src/Data/MonadicStreamFunction/Instances/VectorSpace.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE FlexibleInstances     #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TypeFamilies          #-} {-# LANGUAGE UndecidableInstances  #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -- |@@ -9,8 +8,8 @@ -- Maintainer : ivan.perez@keera.co.uk -- -- 'VectorSpace' instances for 'MSF's that produce vector spaces. This allows--- you to use vector operators with 'MSF's that output vectors, for example, you--- can write:+-- you to use vector operators with 'MSF's that output vectors, for example,+-- you can write: -- -- @ -- msf1 :: MSF Input (Double, Double) -- defined however you want@@ -26,7 +25,7 @@ -- @ -- ----- Instances are provided for the type classes 'RModule' and 'VectorSpace'.+-- Instances are provided for the type class 'VectorSpace'.  -- Note: This module uses undecidable instances, because GHC does not know -- enough to assert that it will be able to determine the type of 's' from the@@ -35,12 +34,13 @@ -- resolved. module Data.MonadicStreamFunction.Instances.VectorSpace where -import Control.Arrow-import Data.VectorSpace--import Control.Arrow.Util+-- External imports+import Control.Arrow    ((>>^))+import Data.VectorSpace (VectorSpace (..)) -import Data.MonadicStreamFunction.Core+-- Internal imports+import Control.Arrow.Util              (constantly, elementwise2)+import Data.MonadicStreamFunction.Core (MSF)  -- | Vector-space instance for 'MSF's. instance (Monad m, VectorSpace v s) => VectorSpace (MSF m a v) s where
src/Data/MonadicStreamFunction/InternalCore.hs view
@@ -1,5 +1,4 @@-{-# LANGUAGE ExplicitForAll #-}-{-# LANGUAGE Rank2Types     #-}+{-# LANGUAGE Rank2Types #-} -- | -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016 -- License    : BSD3@@ -16,41 +15,38 @@ -- 'MSF's are a generalisation of the implementation mechanism used by Yampa, -- Wormholes and other FRP and reactive implementations. ----- This modules defines only the minimal core. Hopefully, other functions can--- be defined in terms of the functions in this module without accessing the--- MSF constuctor.-+-- This modules defines only the minimal core. By default, you should import+-- "Data.MonadicStreamFunction.Core" or "Data.MonadicStreamFunction" whenever+-- possible, and define your functions without accessing the MSF constuctor.+-- Those modules, as well as other modules in dunai, also provide convenient+-- instances. This module may be useful if you are extending dunai with+-- functionality that cannot be (conveniently) expressed using the existing+-- high-level API.  -- NOTE TO IMPLEMENTORS: ----- This module contains the core. Only the core. It should be possible--- to define every function and type outside this module, except for the--- instances for ArrowLoop, ArrowChoice, etc., without access to the--- internal constructor for MSF and the function 'unMSF'.+-- This module contains the core. Only the core. It should be possible to+-- define every function and type outside this module, except for the instances+-- for ArrowLoop, ArrowChoice, etc., without access to the internal constructor+-- for MSF and the function 'unMSF'. ----- It's very hard to know what IS essential to framework and if we start--- adding all the functions and instances that *may* be useful in one--- module.+-- It's very hard to know what IS essential to framework and if we start adding+-- all the functions and instances that *may* be useful in one module. ----- By separating some instances and functions in other modules, we can--- easily understand what is the essential idea and then analyse how it--- is affected by an extension. It also helps demonstrate that something--- works for MSFs + ArrowChoice, or MSFs + ArrowLoop, etc.+-- By separating some instances and functions in other modules, we can easily+-- understand what is the essential idea and then analyse how it is affected by+-- an extension. It also helps demonstrate that something works for MSFs ++-- ArrowChoice, or MSFs + ArrowLoop, etc. ----- To address potential violations of basic design principles (like 'not--- having orphan instances'), the main module Data.MonadicStreamFunction--- exports everything. Users should *never* import this module here--- individually, but the main module instead.+-- To address potential violations of basic design principles (like 'not having+-- orphan instances'), the main module Data.MonadicStreamFunction exports+-- everything. Users should *never* import this module here individually, but+-- the main module instead. module Data.MonadicStreamFunction.InternalCore where --- External-import Control.Applicative-import Control.Arrow-import Control.Category          (Category (..))-import Control.Monad-import Control.Monad.Base-import Control.Monad.Trans.Class-import Prelude                   hiding (id, sum, (.))+-- External imports+import Control.Category (Category (..))+import Prelude          hiding (id, sum, (.))  -- * Definitions @@ -66,7 +62,9 @@ -- | Instance definition for 'Category'. Defines 'id' and '.'. instance Monad m => Category (MSF m) where   id = go-    where go = MSF $ \a -> return (a, go)+    where+      go = MSF $ \a -> return (a, go)+   sf2 . sf1 = MSF $ \a -> do     (b, sf1') <- unMSF sf1 a     (c, sf2') <- unMSF sf2 b@@ -81,17 +79,15 @@ -- -- __Mathematical background:__ The type @a -> m (b, c)@ is a functor in @c@, -- and @MSF m a b@ is its greatest fixpoint, i.e. it is isomorphic to the type--- @a -> m (b, MSF m a b)@, by definition.--- The types @m@, @a@ and @b@ are parameters of the functor.--- Taking a fixpoint is functorial itself, meaning that a morphism--- (a natural transformation) of two such functors gives a morphism--- (an ordinary function) of their fixpoints.+-- @a -> m (b, MSF m a b)@, by definition. The types @m@, @a@ and @b@ are+-- parameters of the functor. Taking a fixpoint is functorial itself, meaning+-- that a morphism (a natural transformation) of two such functors gives a+-- morphism (an ordinary function) of their fixpoints. ----- This is in a sense the most general "abstract" lifting function,--- i.e. the most general one that only changes input, output and side effect--- types, and doesn't influence control flow.--- Other handling functions like exception handling or 'ListT' broadcasting--- necessarily change control flow.+-- This is in a sense the most general "abstract" lifting function, i.e. the+-- most general one that only changes input, output and side effect types, and+-- doesn't influence control flow. Other handling functions like exception+-- handling or 'ListT' broadcasting necessarily change control flow. morphGS :: Monad m2         => (forall c . (a1 -> m1 (b1, c)) -> (a2 -> m2 (b2, c)))           -- ^ The natural transformation. @mi@, @ai@ and @bi@ for @i = 1, 2@@@ -114,14 +110,14 @@  -- | Apply a monadic stream function to a list. ----- Because the result is in a monad, it may be necessary to--- traverse the whole list to evaluate the value in the results to WHNF.--- For example, if the monad is the maybe monad, this may not produce anything--- if the 'MSF' produces 'Nothing' at any point, so the output stream cannot--- consumed progressively.+-- Because the result is in a monad, it may be necessary to traverse the whole+-- list to evaluate the value in the results to WHNF.  For example, if the+-- monad is the maybe monad, this may not produce anything if the 'MSF'+-- produces 'Nothing' at any point, so the output stream cannot consumed+-- progressively. ----- To explore the output progressively, use 'arrM' and '(>>>)'', together--- with some action that consumes/actuates on the output.+-- To explore the output progressively, use 'arrM' and '(>>>)'', together with+-- some action that consumes/actuates on the output. -- -- This is called 'runSF' in Liu, Cheng, Hudak, "Causal Commutative Arrows and -- Their Optimization"
src/Data/MonadicStreamFunction/Parallel.hs view
@@ -7,17 +7,16 @@ -- possible. module Data.MonadicStreamFunction.Parallel where --- External-import Control.Arrow-import GHC.Conc---- Internal-import Data.MonadicStreamFunction-import Data.MonadicStreamFunction.InternalCore+-- External imports+import Control.Arrow (arr, (>>>))+import GHC.Conc      (par, pseq) --- | Run two 'MSF's in parallel, taking advantage of parallelism if---   possible. This is the parallel version of '***'.+-- Internal imports+import Data.MonadicStreamFunction              ()+import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF)) +-- | Run two 'MSF's in parallel, taking advantage of parallelism if possible.+-- This is the parallel version of '***'. (*|*) :: Monad m => MSF m a b -> MSF m c d -> MSF m (a, c) (b, d) msf1 *|* msf2 = MSF $ \(a, c) -> do   (b, msf1') <- unMSF msf1 a
src/Data/MonadicStreamFunction/ReactHandle.hs view
@@ -5,30 +5,27 @@ -- -- 'ReactHandle's. ----- Sometimes it is beneficial to give control to an external main loop,--- for example OpenGL or a hardware-clocked audio server like JACK.--- This module makes Dunai compatible with external main loops.+-- Sometimes it is beneficial to give control to an external main loop, for+-- example OpenGL or a hardware-clocked audio server like JACK. This module+-- makes Dunai compatible with external main loops. module Data.MonadicStreamFunction.ReactHandle where --- External-import Control.Monad.IO.Class-import Data.IORef+-- External imports+import Control.Monad.IO.Class (MonadIO, liftIO)+import Data.IORef             (IORef, newIORef, readIORef, writeIORef) --- Internal-import Data.MonadicStreamFunction-import Data.MonadicStreamFunction.InternalCore+-- Internal imports+import Data.MonadicStreamFunction              (MSF)+import Data.MonadicStreamFunction.InternalCore (unMSF) --- | A storage for the current state of an 'MSF'.--- The 'MSF' may not require input or produce output data,--- all such data must be handled through side effects--- (such as wormholes).+-- | A storage for the current state of an 'MSF'. The 'MSF' may not require+-- input or produce output data, all such data must be handled through side+-- effects (such as wormholes). type ReactHandle m = IORef (MSF m () ()) - -- | Needs to be called before the external main loop is dispatched. reactInit :: MonadIO m => MSF m () () -> m (ReactHandle m) reactInit = liftIO . newIORef-  -- | The callback that needs to be called by the external loop at every cycle. react :: MonadIO m => ReactHandle m -> m ()
src/Data/MonadicStreamFunction/Util.hs view
@@ -1,5 +1,5 @@-{-# LANGUAGE Arrows     #-}-{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE Arrows #-}+{-# LANGUAGE CPP    #-} -- | -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016 -- License    : BSD3@@ -8,37 +8,33 @@ -- Useful auxiliary functions and definitions. module Data.MonadicStreamFunction.Util where --- External-import Control.Arrow-import Control.Category-import Control.Monad-import Control.Monad.Base-import Data.Monoid-import Data.VectorSpace-import Prelude            hiding (id, (.))+-- External imports+import Control.Arrow    (arr, returnA, (&&&), (<<<), (>>>))+import Control.Category (id, (.))+import Control.Monad    (when)+import Data.VectorSpace (VectorSpace, zeroVector, (^+^))+import Prelude          hiding (id, (.)) --- Internal-import Control.Monad.Trans.MSF.State-import Data.MonadicStreamFunction.Core+#if !MIN_VERSION_base(4,8,0)+import Data.Monoid (Monoid, mempty, mappend)+#endif++-- Internal imports+import Data.MonadicStreamFunction.Core                  (MSF, arrM, feedback) import Data.MonadicStreamFunction.Instances.ArrowChoice ()  -- * Streams and sinks --- | A stream is an 'MSF' that produces outputs, while ignoring the input.--- It can obtain the values from a monadic context.+-- | A stream is an 'MSF' that produces outputs, while ignoring the input. It+-- can obtain the values from a monadic context. type MStream m a = MSF m () a --- | A sink is an 'MSF' that consumes inputs, while producing no output.--- It can consume the values with side effects.-type MSink   m a = MSF m a ()---- * Lifting--+-- | A sink is an 'MSF' that consumes inputs, while producing no output. It+-- can consume the values with side effects.+type MSink m a = MSF m a ()  -- * Analogues of 'map' and 'fmap' - -- | 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)@@ -59,17 +55,13 @@  -- * Delays --- See also: 'iPre'- -- | Delay a signal by one sample. iPre :: Monad m      => a         -- ^ First output      -> MSF m a a--- iPre firsta = MSF $ \a -> return (firsta, iPre a) iPre firsta = feedback firsta $ arr swap-  where swap (a,b) = (b, a)--- iPre firsta = next firsta identity-+  where+    swap (a, b) = (b, a)  -- | Preprends a fixed output to an 'MSF'. The first input is completely -- ignored.@@ -82,15 +74,20 @@ next :: Monad m => b -> MSF m a b -> MSF m a b next b sf = sf >>> iPre b --- | Buffers and returns the elements in FIFO order,---   returning 'Nothing' whenever the buffer is empty.+-- | Buffers and returns the elements in FIFO order, returning 'Nothing'+-- whenever the buffer is empty. fifo :: Monad m => MSF m [a] (Maybe a)-fifo = feedback [] $ proc (as, accum) -> do-  let accum' = accum ++ as-  returnA -< case accum' of-    []       -> (Nothing, [])-    (a : as) -> (Just a , as)+fifo = feedback [] (arr (safeSnoc . uncurry fifoAppend))+  where+    -- | Append a new list to an accumulator in FIFO order.+    fifoAppend :: [x] -> [x] -> [x]+    fifoAppend as accum = accum ++ as +    -- | Split a list into the head and the tail.+    safeSnoc :: [x] -> (Maybe x, [x])+    safeSnoc []     = (Nothing, [])+    safeSnoc (x:xs) = (Just x, xs)+ -- * Folding  -- ** Folding for 'VectorSpace' instances@@ -120,16 +117,15 @@  -- ** Generic folding \/ accumulation --- | Applies a function to the input and an accumulator,--- outputting the updated accumulator.--- Equal to @\f s0 -> feedback s0 $ arr (uncurry f >>> dup)@.+-- | Applies a function to the input and an accumulator, outputting the updated+-- 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') --- | Applies a transfer function to the input and an accumulator,--- returning the updated accumulator and output.+-- | Applies a transfer function to the input and an accumulator, returning the+-- updated accumulator and output. mealy :: Monad m => (a -> s -> (b, s)) -> s -> MSF m a b mealy f s0 = feedback s0 $ arr $ uncurry f @@ -141,14 +137,13 @@ unfold f a = feedback a (arr (snd >>> f))  -- | 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@.+-- 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 = unfold $ f >>> dup   where     dup a = (a, a) - -- * Debugging  -- | Outputs every input sample, with a given message prefix.@@ -163,7 +158,11 @@  -- | 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 :: (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