packages feed

dunai 0.7.0 → 0.14.2

raw patch · 25 files changed

Files

+ CHANGELOG view
@@ -0,0 +1,200 @@+2026-10-21+        * Version bump (0.14.2) (#475).+        * Fix error in execution of `cabal update` in CI (#469).+        * Constrain versions of `MonadRandom` for GHC < 8.0 (#470).+        * Bump upper bounds on `hlint`, `time`, `transformers-compat` (#471).+        * Change repository protocol in Cabal file to https (#473).++2025-02-27+        * Version bump (0.14.1) (#465).+        * Change contact address (#462).+        * Remove emails from CHANGELOG (#463).++2024-12-21+        * Version bump (0.14.0) (#460).+        * Increase upper bounds on filepath, tasty, time, hlint (#448).+        * Remove deprecated functions related to list-t (#445).++2024-10-21+        * Version bump (0.13.2) (#442).++2024-08-21+        * Version bump (0.13.1) (#430).+        * Increase upper bounds on transformers (#427).+        * Thanks to @tomsmeding.++2024-06-21+        * Version bump (0.13.0) (#420).+        * Implement List interface using list-transformer (#418).++2024-04-23+        * Version bump (0.12.3) (#411).+        * Fix typo in documentation (#410).++2024-02-21+        * Version bump (0.12.2) (#398).+        * Limit version of transformers to < 0.6 (#405).++2023-12-21+        * Version bump (0.12.1) (#395).+        * Remove postgresql repo before installation in CI script (#392).+        * Add version bounds to dependencies (#393).+        * Mark package as uncurated (#394).+        * Fix typo in CHANGELOG (#396).++2023-10-21+        * Version bump (0.12.0) (#388).+        * Increase max-backjumps in CI setup (#381).+        * Document GHC 9.8.1 support in readme (#387).++2023-08-21+        * Version bump (0.11.2) (#377).+        * Introduce benchmark (#375).++2023-06-21+        * Version bump (0.11.1) (#372).+        * Reflect new contribution process in README (#362).++2023-04-21+        * Version bump (0.11.0) (#358).+        * Update paper links to ACM, personal website (#346).++2023-02-21+        * Version bump (0.10.1) (#345).+        * Enable FlexibleContexts in VectorSpace instance module (#344).++2023-02-21+        * Version bump (0.10.0) (#342).+        * Implement dot in MSF's instance of VectorSpace (#298).+        * Adjust version bounds for simple-affine-space (#343).++2022-12-21+        * Version bump (0.9.2) (#340).+        * Bump version bounds for MonadRandom (#337).+        * Adjust to work with simple-affine-space-0.2 (#339).++2022-10-21+        * Version bump (0.9.1) (#335).+        * Add link to updated paper examples from README (#319).+        * Update Travis script (#333).+        * Style fixes (partial) (#334).++2022-08-21+        * Version bump (0.9.0) (#313).+        * Document haskell-titan support in readme (#176).+        * Re-format CHANGELOG for readability (#308).+        * Add version bounds for dependencies (#303).+        * Consistency in condition used to check GHC/base version (#295).+        * Fix typo on documentation (#304).+        * Document GHC 9.4.1 titan support in readme (#309).++2022-06-21+        * Version bump (0.8.3) (#302).+        * 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).+        * Re-structure README (#300).++2022-04-21+        * Version bump (0.8.2) (#280).+        * Syntax rules (#271).+        * Declare CHANGELOG (#273).+        * Declare subdir of source-repository (#272).+        * Fix haddock syntax error in documentation of switch (#274).+        * Introduce new dSwitch function (#275).+        * Syntax rules (#277).+        * Remove unused module Ultrametric (#278).+        * Remove unused module CausalCommutative (#279).++2021-10-21+        * Version bump (0.8.1).+        * Code cleaning.+        * Update example in README to new API.+        * Fix broken link in README.+        * Update badge in README.+        * Fix typo in README.+        * Thanks: @DireWolf707.++2021-09-06+        * Version bump (0.8.0).+        * Code cleaning.+        * List GHC 8.10 as supported in README.+        * Thanks: @walseb, @turion, @bgluzman, @mezzomondo.++2020-04-18+        * Version bump (0.7.0).+        * Add new utilities.+        * Fix behaviour of listToMaybeS.+        * List GHC 8.8 as supported in README.+        * Cleaning and hlinting changes.+        * Thanks: @turion, @Linearity.++2020-01-25+        * Version bump (0.6.0).+        * Use simple-affine-space as dependency.+        * Remove Data.VectorSpace.+        * Fix error in documentation of embed.+        * List GHC 8.6 as supported in README.+        * Add links to videos to README.+        * Fix typos in README.+        * Thanks: @chriz-keera, @turion, @Rizary, @dynomite567,+          @alexmarginean16.++2019-09-29+        * Version bump (0.5.2.1).+        * Expose List support.+        * Fix error in List on older versions of GHC.++2019-09-29+        * Version bump (0.5.2).+        * Expose List support.+        * Fix error in List support implementation.++2018-11-03+        * Version bump (0.5.1).+        * Fix failed patterns in do notation.+        * Thanks: @turion, @ggreif.++2018-11-03+        * Version bump (0.5).+        * Rename lifting functions.+        * Move definitions around.+        * Thanks: @turion.++2017-12-05+        * Version bump (0.4).+        * Add support for random numbers using MonadRandom.+        * Remove MSF constructor from many definitions.+        * Add support for older GHC versions.+        * Move some definitions/modules around.+        * Change licenses in examples, update them to use new API.+        * Thanks: @thalerjonathan, @turion.++2017-10-31+        * Version bump (0.3).+        * Add repo URL to cabal file.+        * Add documentation to cabal file.+        * Re-structure modules.+        * Complete documentation in code.+        * Add stack configuration file.+        * Fix compilation errors with older versions of GHC.+        * Update examples to use new API.++Copyright (c) 2016, Ivan Perez and Manuel Bärenz.+All rights reserved.
+ benchmarks/Bench.hs view
@@ -0,0 +1,162 @@+-- |+-- Description : A benchmark for dunai.+-- Copyright   : (c) Ivan Perez, 2023+-- Authors     : Ivan Perez+-- Maintainer  : ivan.perez@keera.co.uk+-- License     : BSD3+--+-- A benchmark for Dunai.+module Main where++import Criterion             (bench, bgroup, nf)+import Criterion.Main        (defaultConfig, defaultMainWith)+import Criterion.Types       (Config (csvFile, resamples, verbosity),+                              Verbosity (Quiet))+import Data.Functor.Identity (runIdentity)+import Data.Time.Format      (defaultTimeLocale, formatTime)+import Data.Time.LocalTime   (getZonedTime)+import System.Environment    (getArgs, withArgs)+import System.FilePath       ((</>))++import qualified Control.Category as C++import Data.MonadicStreamFunction++-- | Run all benchmarks.+main :: IO ()+main = do+  config <- customConfig+  withArgs [] $+    defaultMainWith config+       [ bgroup "basic"+                [ bench "identity" $ nf basicIdentity 10000+                , bench "id"       $ nf basicId       10000+                ]+       , bgroup "compositions"+                [ bench "identity" $ nf composeIdentity 10000+                , bench "idid"     $ nf composeIdId     10000+                , bench "plus"     $ nf composePlus     10000+                , bench "plusplus" $ nf composePlusPlus 10000+                , bench "plusmult" $ nf composePlusMult 10000+                , bench "mult"     $ nf composeMult     10000+                , bench "multmult" $ nf composeMultMult 10000+                ]+       , bgroup "counter"+                [ bench "counter1" $ nf counter1 10000+                , bench "counter2" $ nf counter2 10000+                ]+       ]++-- * Benchmarks++-- ** Basic++-- | Dunai's specialized identity function.+basicIdentity :: Int -> [Int]+basicIdentity n = runIdentity $ embed sf stream+  where+    sf     = C.id+    stream = replicate n 1++-- | Standard function identity lifted to SFs.+basicId :: Int -> [Int]+basicId n = runIdentity $ embed sf stream+  where+    sf     = arr id+    stream = replicate n 1++-- ** Compositions++-- | Composition of Dunai's specialized identity function.+composeIdentity :: Int -> [Int]+composeIdentity n = runIdentity $ embed sf stream+  where+    sf     = C.id >>> C.id+    stream = replicate n 1++-- | Composition of standard function identity lifted to SFs.+composeIdId :: Int -> [Int]+composeIdId n = runIdentity $ embed sf stream+  where+    sf     = arr id >>> arr id+    stream = replicate n 1++-- | Plus operation.+--+-- This is not a composition; it merely exists to serve as a comparison with+-- composePlusPlus.+composePlus :: Int -> [Int]+composePlus n = runIdentity $ embed sf stream+  where+    sf     = arr (+3)+    stream = take n [1..]++-- | Composition of addition lifted to SFs.+composePlusPlus :: Int -> [Int]+composePlusPlus n = runIdentity $ embed sf stream+  where+    sf     = arr (+1) >>> arr (+2)+    stream = take n [1..]++-- | Composition of addition with multiplication, lifted to SFs.+composePlusMult :: Int -> [Int]+composePlusMult n = runIdentity $ embed sf stream+  where+    sf     = arr (+100) >>> arr (*2)+    stream = take n [10..]++-- | Multiplication operation.+--+-- This is not a composition; it merely exists to serve as a comparison with+-- composeMultMult.+composeMult :: Int -> [Int]+composeMult n = runIdentity $ embed sf stream+  where+    sf     = arr (*20)+    stream = take n [10..]++-- | Composition of multiplication lifted to SFs.+composeMultMult :: Int -> [Int]+composeMultMult n = runIdentity $ embed sf stream+  where+    sf     = arr (*10) >>> arr (*2)+    stream = take n [10..]++-- ** Counter++-- | Counter without explicit seq.+counter1 :: Int -> [Int]+counter1 n = runIdentity $ embed sf stream+  where+    sf     = feedback 0 (arr (dup . uncurry (+)))+    stream = replicate n 1++    dup x = (x, x)++-- | Counter with explicit seq.+counter2 :: Int -> [Int]+counter2 n = runIdentity $ embed sf stream+  where+    sf     = feedback 0 (arr ((\x -> x `seq` (x, x)). uncurry (+)))+    stream = replicate n 1++-- * Auxiliary functions++-- Construct a config with increased number of sampling+-- and a custom name for the report.+customConfig :: IO Config+customConfig = do+  args <- getArgs++  let dir = case args of+              []     -> "."+              (x:xs) -> x++  -- Custom filename using the current time+  timeString <- (formatTime defaultTimeLocale "%F-%H%M%S") <$> getZonedTime+  let filename = concat [ timeString, "-", "bench.csv" ]++  return $ defaultConfig { csvFile   = Just $ dir </> filename+                         , resamples = 100000+                         , verbosity = Quiet+                         }
dunai.cabal view
@@ -1,14 +1,53 @@-name:                dunai-version:             0.7.0-synopsis:            Generalised reactive framework supporting classic, arrowized and monadic FRP.-homepage:            https://github.com/ivanperez-keera/dunai+-- Copyright (c) 2016 - Ivan Perez and Manuel Bärenz - All rights reserved+--+-- Redistribution and use in source and binary forms, with or without+-- modification, are permitted provided that the following conditions are met:+--+--     * Redistributions of source code must retain the above copyright+--       notice, this list of conditions and the following disclaimer.+--+--     * Redistributions in binary form must reproduce the above+--       copyright notice, this list of conditions and the following+--       disclaimer in the documentation and/or other materials provided+--       with the distribution.+--+--     * Neither the name of Ivan Perez and Manuel Bärenz nor the names of+--       other contributors may be used to endorse or promote products derived+--       from this software without specific prior written permission.+--+-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+-- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+cabal-version: >= 1.10+build-type:    Simple++name:          dunai+version:       0.14.2+author:        Ivan Perez, Manuel Bärenz+maintainer:    contact@ivanperez.io+homepage:      https://github.com/ivanperez-keera/dunai+license:       BSD3+license-file:  LICENSE+copyright:     Copyright (c) 2016 - Ivan Perez and Manuel Bärenz+category:      Reactivity, FRP+synopsis:+  Generalised reactive framework supporting classic, arrowized and monadic FRP. description:   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)@-  that executes one step of a simulation, and produces an output in a monadic-  context, and a continuation to be used for future steps.+  transformations defined by a function+  @unMSF :: MSF m a b -> a -> m (b, MSF m a b)@ that executes one step of a+  simulation, and produces an output in a monadic context, and a continuation+  to be used for future steps.   .   MSFs are a generalisation of the implementation mechanism used by Yampa,   Wormholes and other FRP and reactive implementations.@@ -25,115 +64,185 @@   with @ListT@ gives rise to parallelism with broadcasting.   .   MSFs can be used to implement many FRP variants, including Arrowized FRP,-  Classic FRP, and plain reactive programming. Arrowized and applicative-  syntax are both supported.+  Classic FRP, and plain reactive programming. Arrowized and applicative syntax+  are both supported.   .   For a very detailed introduction to MSFs, see:   <http://dl.acm.org/citation.cfm?id=2976010>-  (mirror: <http://www.cs.nott.ac.uk/~psxip1/#FRPRefactored>).-license:             BSD3-license-file:        LICENSE-author:              Ivan Perez, Manuel Bärenz-maintainer:          ivan.perez@keera.co.uk--- copyright:-category:            Reactivity, FRP-build-type:          Simple--- extra-source-files:-cabal-version:       >=1.10+  (mirror: <http://ivanperez.io/#FRPRefactored>). ++x-curation: uncurated+++extra-source-files:+  CHANGELOG+++source-repository head+  type:     git+  location: https://github.com/ivanperez-keera/dunai.git+  subdir:   dunai++ -- You can disable the hlint test suite with -f-test-hlint flag test-hlint   description: Enable hlint test suite-  default: False-  manual: True+  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+  default:     False+  manual:      True + library-  exposed-modules:   Control.Monad.Trans.MSF-                     Control.Monad.Trans.MSF.Except-                     Control.Monad.Trans.MSF.Maybe-                     Control.Monad.Trans.MSF.List-                     Control.Monad.Trans.MSF.Random-                     Control.Monad.Trans.MSF.Reader-                     Control.Monad.Trans.MSF.RWS-                     Control.Monad.Trans.MSF.State-                     Control.Monad.Trans.MSF.Writer-                     Data.MonadicStreamFunction-                     Data.MonadicStreamFunction.Core-                     Data.MonadicStreamFunction.Async-                     Data.MonadicStreamFunction.Instances.ArrowChoice-                     Data.MonadicStreamFunction.Instances.ArrowLoop-                     Data.MonadicStreamFunction.Instances.ArrowPlus-                     Data.MonadicStreamFunction.Instances.Num-                     Data.MonadicStreamFunction.Instances.VectorSpace-                     Data.MonadicStreamFunction.InternalCore-                     Data.MonadicStreamFunction.Parallel-                     Data.MonadicStreamFunction.ReactHandle-                     Data.MonadicStreamFunction.Util+  exposed-modules:+    Control.Monad.Trans.MSF+    Control.Monad.Trans.MSF.Except+    Control.Monad.Trans.MSF.List+    Control.Monad.Trans.MSF.Maybe+    Control.Monad.Trans.MSF.Random+    Control.Monad.Trans.MSF.Reader+    Control.Monad.Trans.MSF.RWS+    Control.Monad.Trans.MSF.State+    Control.Monad.Trans.MSF.Writer+    Data.MonadicStreamFunction+    Data.MonadicStreamFunction.Async+    Data.MonadicStreamFunction.Core+    Data.MonadicStreamFunction.Instances.ArrowChoice+    Data.MonadicStreamFunction.Instances.ArrowLoop+    Data.MonadicStreamFunction.Instances.ArrowPlus+    Data.MonadicStreamFunction.Instances.Num+    Data.MonadicStreamFunction.Instances.VectorSpace+    Data.MonadicStreamFunction.InternalCore+    Data.MonadicStreamFunction.Parallel+    Data.MonadicStreamFunction.ReactHandle+    Data.MonadicStreamFunction.Util -  other-modules:     Control.Arrow.Util+  other-modules:+    Control.Arrow.Util -  build-depends:     base >=4.6 && < 5,-                     transformers,-                     transformers-base,-                     MonadRandom,-                     simple-affine-space+  build-depends:+      base >= 4.6 && < 5+    , MonadRandom         >= 0.2   && < 0.7+    , list-transformer    >= 1.1.1 && < 1.2+    , simple-affine-space >= 0.2   && < 0.3+    , transformers        >= 0.3   && < 0.7+    , transformers-base   >= 0.4   && < 0.5 -  hs-source-dirs:    src-  default-language:  Haskell2010-  ghc-options:       -Wall -fno-warn-unused-do-bind+  default-language:+    Haskell2010 +  hs-source-dirs:+    src++  ghc-options:+    -Wall -fno-warn-unused-do-bind+   if impl(ghc <= 7.8.4)-    build-depends: transformers-compat+    build-depends:+        MonadRandom         >= 0.2 && < 0.6+      , transformers-compat >= 0.3 && < 0.9+      , void                >= 0.1 && < 0.8 +  if impl(ghc < 8.0)+    build-depends:+     MonadRandom >= 0.2 && < 0.6.2.1+ test-suite hlint-  type: exitcode-stdio-1.0-  main-is: HLintMain.hs-  hs-source-dirs: tests-  default-language:  Haskell2010+  type:+    exitcode-stdio-1.0++  main-is:+    HLintMain.hs++  default-language:+    Haskell2010++  hs-source-dirs:+    tests+   if !flag(test-hlint)-    buildable: False+    buildable:+      False   else     build-depends:-      base,-      hlint >= 1.7+        base  >= 4   && < 5+      , hlint >= 1.7 && < 3.11  -- Verify that the code is thoroughly documented test-suite haddock-coverage-  type: exitcode-stdio-1.0-  main-is: HaddockCoverage.hs-  ghc-options: -Wall-  hs-source-dirs: tests-  default-language:  Haskell2010+  type:+    exitcode-stdio-1.0 +  main-is:+    HaddockCoverage.hs++  default-language:+    Haskell2010++  hs-source-dirs:+    tests++  ghc-options:+    -Wall+   if !flag(test-doc-coverage)-    buildable: False+    buildable:+      False   else     build-depends:-      base >= 4 && < 5,-      directory,-      filepath,-      process,-      regex-posix+        base           >= 4       && < 5+      , directory      >= 1.2     && < 1.4+      , filepath       >= 1.3.0.1 && < 1.6+      , process        >= 1.1.0.2 && < 1.7+      , regex-posix    >= 0.95    && < 0.97 -source-repository head-  type:     git-  location: git@github.com:ivanperez-keera/dunai.git  test-suite regression-tests-  type: exitcode-stdio-1.0-  main-is: RegressionTests.hs-  ghc-options: -Wall-  hs-source-dirs: tests-  default-language:  Haskell2010+  type:+    exitcode-stdio-1.0++  main-is:+    RegressionTests.hs++  default-language:+    Haskell2010++  hs-source-dirs:+    tests++  ghc-options:+    -Wall+   build-depends:-    base >=4 && <5,-    transformers,-    dunai,-    tasty,-    tasty-hunit+      base         >= 4   && < 5+    , transformers >= 0.3 && < 0.7+    , tasty        >= 0.1 && < 1.6+    , tasty-hunit  >= 0.8 && < 0.11++    , dunai+++benchmark dunai-bench+  type:+    exitcode-stdio-1.0++  main-is:+    Bench.hs++  build-depends:+       base      >= 4       && < 5+     , criterion >= 0.5.0.0 && < 1.7+     , filepath  >= 1.3.0.1 && < 1.6+     , time      >= 1.4     && < 1.17+     , dunai++  default-language:+    Haskell2010++  hs-source-dirs:+    benchmarks
src/Control/Arrow/Util.hs view
@@ -1,24 +1,21 @@--- | Utility functions to work with 'Arrow's.+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk+--+-- 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 #-} --- import Control.Category (id)--- import Prelude hiding (id)---- (&&&!) :: Arrow a => a b c -> a b () -> a b c--- a1 &&&! a2 = (a1 &&& a2) >>> arr fst---- 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 = (^<<)
src/Control/Monad/Trans/MSF.hs view
@@ -1,6 +1,9 @@-{-# LANGUAGE Rank2Types #-}---- | This module reexports nearly all submodules. RWS is not exported since+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk+--+-- 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.Except@@ -12,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,32 +1,43 @@-{-# LANGUAGE Arrows              #-}-{-# LANGUAGE CPP                 #-}-{-# LANGUAGE Rank2Types          #-}-{-# LANGUAGE TupleSections       #-}--- | '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.+{-# LANGUAGE Arrows     #-}+{-# LANGUAGE CPP        #-}+{-# LANGUAGE Rank2Types #-}+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk+--+-- '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+    ( module Control.Monad.Trans.MSF.Except+    , module Control.Monad.Trans.Except+    )+  where --- External+-- External imports+#if !MIN_VERSION_base(4,8,0)+import           Control.Applicative        (Applicative (..), (<$>))+#endif -import           Control.Applicative+import           Control.Arrow              (arr, returnA, (<<<), (>>>)) 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              (ap, liftM)+import           Control.Monad.Trans.Class  (lift)+import           Control.Monad.Trans.Except hiding (liftCallCC, liftListen,+                                             liftPass)+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+#if !MIN_VERSION_base(4,10,0) fromLeft  :: a -> Either a b -> a fromLeft  _ (Left  a) = a fromLeft  a (Right _) = a@@ -45,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@@ -64,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 @@ -81,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 @@ -177,40 +184,36 @@   return = pure   MSFExcept msf >>= f = MSFExcept $ handleExceptT msf $ runMSFExcept . f -handleExceptT-  :: Monad m-  => MSF (ExceptT e1 m) a b-  -> (e1 -> MSF (ExceptT e2 m) a b)-  -> MSF (ExceptT e2 m) a b+-- | Execute an MSF and, if it throws an exception, recover by switching 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 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 @@ -218,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           -< ()@@ -227,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@@ -265,14 +261,35 @@ reactimateB :: Monad m => MSF m () Bool -> m () reactimateB sf = reactimateExcept $ try $ liftTransS sf >>> throwOn () --- * Analog to Yampa's switch, with Maybe instead of Event+-- | 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),+-- 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),+-- 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+  where+    ef = feedback Nothing $ proc (a, me) -> do+           throwMaybe    -< me+           liftTransS sf -< a+ -- | 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@@ -283,12 +300,16 @@        -> 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))           -> MSF m1 a b1           -> MSF m2 a b2
src/Control/Monad/Trans/MSF/List.hs view
@@ -1,39 +1,68 @@ {-# LANGUAGE CPP #-}+-- |+-- 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). module Control.Monad.Trans.MSF.List-  ( module Control.Monad.Trans.MSF.List-  , module Control.Monad.Trans.List-  ) where---- External-import Control.Monad.Trans.List-  hiding (liftCallCC, liftCatch) -- Avoid conflicting exports+    ( module Control.Monad.Trans.MSF.List+    , module List+    )+  where +-- External imports #if !MIN_VERSION_base(4,8,0) import Control.Applicative ((<$>)) #endif --- Internal-import Data.MonadicStreamFunction+import           Control.Monad    (sequence)+import           List.Transformer (ListT (ListT, next), Step (..), fold, select)+import qualified List.Transformer as List++-- 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 (toList . flip unMSF a) msfs+      return (bs, widthFirst' msfs') +    toList :: (Functor m, Monad m) => ListT m a -> m [a]+    toList = fmap reverse . fold (flip (:)) [] id --- 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+sequenceS msfs = MSF $ \a -> sequence' $ apply a <$> msfs   where+    sequence' :: Monad m => [m a] -> ListT m a+    sequence' xs = ListT $ next <$> select =<< sequence xs++    apply :: Monad m => a -> MSF m a b -> m (b, MSF (ListT m) a b)     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]@@ -45,4 +74,3 @@       (b, sf')   <- unMSF sf a       (bs, sf'') <- consume sf' as       b `seq` return (b:bs, sf'')-
src/Control/Monad/Trans/MSF/Maybe.hs view
@@ -1,23 +1,30 @@-{-# 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.--}+{-# LANGUAGE Arrows #-}+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk+--+-- 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-  , maybeToExceptS-  ) where+    ( module Control.Monad.Trans.MSF.Maybe+    , module Control.Monad.Trans.Maybe+    , maybeToExceptS+    )+  where --- External-import Control.Monad.Trans.Maybe-  hiding (liftCallCC, liftCatch, liftListen, liftPass) -- Avoid conflicting exports+-- 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") @@ -45,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@@ -66,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,26 +1,34 @@--- | This module combines the wrapping and running functions---   for the 'Reader', 'Writer' and 'State' monad layers in a single layer.+{-# LANGUAGE CPP #-}+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk --+-- This module combines the wrapping and running functions for the 'Reader',+-- 'Writer' and 'State' monad layers in a single layer.+-- -- It is based on the _strict_ 'RWS' monad 'Control.Monad.Trans.RWS.Strict',--- so when combining it with other modules such as @mtl@'s,--- the strict version has to be included, i.e. 'Control.Monad.RWS.Strict'--- instead of 'Control.Monad.RWS' or 'Control.Monad.RWS.Lazy'.+-- so when combining it with other modules such as @mtl@'s, the strict version+-- 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-import Control.Monad.Trans.RWS.Strict-  hiding (liftCallCC, liftCatch) -- Avoid conflicting exports-import Data.Monoid+-- External imports+import Control.Monad.Trans.RWS.Strict hiding (liftCallCC, liftCatch)++#if !MIN_VERSION_base(4,8,0) import Data.Functor ((<$>))+import Data.Monoid  (Monoid)+#endif --- Internal-import Data.MonadicStreamFunction+-- 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
@@ -1,47 +1,47 @@--- | In this module, 'MSF's in a monad supporting random number generation---   (i.e. having the 'RandT' layer in its stack) can be run.---   Running means supplying an initial random number generator,---   where the update of the generator at every random number generation---   is already taken care of.+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk -----   Under the hood, 'RandT' is basically just 'StateT',---   with the current random number generator as mutable state.---{-# LANGUAGE Arrows              #-}+-- In this module, 'MSF's in a monad supporting random number generation (i.e.+-- having the 'RandT' layer in its stack) can be run. Running means supplying+-- an initial random number generator, where the update of the generator at+-- every random number generation is already taken care of.+--+-- 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 Data.MonadicStreamFunction-import Control.Monad.Trans.MSF.State+-- 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@@ -50,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@@ -59,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 @@ -68,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,25 +1,29 @@-{-# LANGUAGE Rank2Types          #-}---- | 'MSF's with a 'Reader' monadic layer.+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk --+-- 'MSF's with a 'Reader' monadic layer.+-- -- This module contains functions to work with 'MSF's that include a 'Reader' -- monadic layer. This includes functions to create new 'MSF's 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.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-import Control.Monad.Trans.Reader-  hiding (liftCallCC, liftCatch) -- Avoid conflicting exports+-- 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 @@ -33,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,6 +1,11 @@-{-# LANGUAGE Rank2Types #-}--- | 'MSF's with a 'State' monadic layer.+{-# LANGUAGE CPP #-}+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk --+-- 'MSF's with a 'State' monadic layer.+-- -- This module contains functions to work with 'MSF's that include a 'State' -- monadic layer. This includes functions to create new 'MSF's that include an -- additional layer, and functions to flatten that layer out of the 'MSF`'s@@ -11,24 +16,28 @@ -- 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-import Control.Monad.Trans.State.Strict-  hiding (liftCallCC, liftCatch, liftListen, liftPass) -- Avoid conflicting exports-import Data.Tuple (swap)+-- External imports+#if !MIN_VERSION_base(4,8,0)+import Control.Applicative ((<$>))+#endif --- Internal-import Data.MonadicStreamFunction.Core-import Data.MonadicStreamFunction.InternalCore+import Control.Arrow                    (arr, (>>>))+import Control.Monad.Trans.State.Strict hiding (liftCallCC, liftCatch,+                                         liftListen, liftPass)+import Data.Tuple                       (swap) +-- Internal imports+import Data.MonadicStreamFunction.Core (MSF, morphGS, feedback)+ -- * 'State' 'MSF' running and wrapping  -- | Build an 'MSF' in the 'State' monad from one that takes the state as an@@ -46,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,5 +1,11 @@--- | 'MSF's with a 'Writer' monadic layer.+{-# LANGUAGE CPP #-}+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk --+-- 'MSF's with a 'Writer' monadic layer.+-- -- This module contains functions to work with 'MSF's that include a 'Writer' -- monadic layer. This includes functions to create new 'MSF's that include an -- additional layer, and functions to flatten that layer out of the 'MSF`'s@@ -10,20 +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-import Control.Monad.Trans.Writer.Strict-  hiding (liftCallCC, liftCatch, pass) -- Avoid conflicting exports+-- External imports+import Control.Monad.Trans.Writer.Strict hiding (liftCallCC, liftCatch, pass)++#if !MIN_VERSION_base(4,8,0) import Data.Functor ((<$>))-import Data.Monoid+import Data.Monoid  (Monoid)+#endif --- Internal-import Data.MonadicStreamFunction+-- Internal imports+import Data.MonadicStreamFunction (MSF, morphGS)  -- * 'Writer' 'MSF' running and wrapping 
src/Data/MonadicStreamFunction.hs view
@@ -1,41 +1,45 @@--- | Monadic Stream Functions are synchronized stream functions---   with side effects.+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk -----   'MSF's are defined by a function---   @unMSF :: MSF m a b -> a -> m (b, MSF m a b)@---   that executes one step of a simulation, and produces an output in a---   monadic context, and a continuation to be used for future steps.+-- Monadic Stream Functions are synchronized stream functions with side+-- effects. -----   See the module "Data.MonadicStreamFunction.Core" for details.+-- 'MSF's are defined by a function+-- @unMSF :: MSF m a b -> a -> m (b, MSF m a b)@+-- that executes one step of a simulation, and produces an output in a monadic+-- context, and a continuation to be used for future steps. -----   'MSF's are a generalisation of the implementation mechanism used by Yampa,---   Wormholes and other FRP and reactive implementations.+-- See the module "Data.MonadicStreamFunction.Core" for details. -----   When combined with different monads, they produce interesting effects. For---   example, when combined with the 'Maybe' monad, they become transformations---   that may stop producing outputs (and continuations). The 'Either' monad---   gives rise to 'MSF's that end with a result (akin to Tasks in Yampa, and---   Monadic FRP).+-- 'MSF's are a generalisation of the implementation mechanism used by Yampa,+-- Wormholes and other FRP and reactive implementations. -----   Flattening, that is, going from some structure @MSF (t m) a b@ to @MSF m a b@---   for a specific transformer @t@ often gives rise to known FRP constructs.---   For instance, flattening with 'EitherT' gives rise to switching, and---   flattening with 'ListT' gives rise to parallelism with broadcasting.+-- When combined with different monads, they produce interesting effects. For+-- example, when combined with the 'Maybe' monad, they become transformations+-- that may stop producing outputs (and continuations). The 'Either' monad+-- gives rise to 'MSF's that end with a result (akin to Tasks in Yampa, and+-- Monadic FRP). -----   'MSF's can be used to implement many FRP variants, including Arrowized FRP,---   Classic FRP, and plain reactive programming. Arrowized and applicative---   syntax are both supported.+-- Flattening, that is, going from some structure @MSF (t m) a b@ to @MSF m a+-- b@ for a specific transformer @t@ often gives rise to known FRP constructs.+-- For instance, flattening with 'EitherT' gives rise to switching, and+-- flattening with 'ListT' gives rise to parallelism with broadcasting. -----   For a very detailed introduction to 'MSF's, see:---   <http://dl.acm.org/citation.cfm?id=2976010>---   (mirror: <http://www.cs.nott.ac.uk/~psxip1/#FRPRefactored>).+-- 'MSF's can be used to implement many FRP variants, including Arrowized FRP,+-- Classic FRP, and plain reactive programming. Arrowized and applicative+-- syntax are both supported. -----   Apart from the modules exported, this module exports instances from:+-- For a very detailed introduction to 'MSF's, see:+-- <http://dl.acm.org/citation.cfm?id=2976010>+-- (mirror: <http://www.cs.nott.ac.uk/~psxip1/#FRPRefactored>). -----   - "Data.MonadicStreamFunction.Instances.ArrowChoice"---   - "Data.MonadicStreamFunction.Instances.ArrowLoop"---   - "Data.MonadicStreamFunction.Instances.ArrowPlus"-+-- Apart from the modules exported, this module exports instances from:+--+-- - "Data.MonadicStreamFunction.Instances.ArrowChoice"+-- - "Data.MonadicStreamFunction.Instances.ArrowLoop"+-- - "Data.MonadicStreamFunction.Instances.ArrowPlus" module Data.MonadicStreamFunction   ( module Control.Arrow   , module Data.MonadicStreamFunction.Core@@ -43,17 +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
@@ -1,59 +1,61 @@--- | This module contains operations on monadic streams that are asynchronous,---   i.e. that change the speed at which data enters or leaves the 'MSF'.-+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk+--+-- This module contains operations on monadic streams that are asynchronous,+-- 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-import Data.MonadicStreamFunction.Util (MStream)--{- |-Concatenates a monadic stream of lists to a monadic stream.-The stream of lists will be called exactly when new data is needed.--Example:-->>> 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-Enter a list of Ints:-[]-Enter a list of Ints:-[]-Enter a list of Ints:-[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:-->>> let boolToList b = if b then ["Yes"] else []->>> let everyOddEmpty = count >>> arr (even >>> boolToList)->>> reactimate $ concatS everyOddEmpty >>> arrM print-"Yes"-"Yes"-"Yes"-"Yes"-"Yes"-...--But this will be caught in a loop:+-- Internal imports+import Data.MonadicStreamFunction.InternalCore (MSF(MSF, unMSF))+import Data.MonadicStreamFunction.Util         (MStream) ->>> let after3Empty = count >>> arr ((<= 3) >>> boolToList)->>> reactimate $ concatS after3Empty  >>> arrM print-"Yes"-"Yes"-"Yes"-^CInterrupted.--}+-- |+-- Concatenates a monadic stream of lists to a monadic stream.+-- The stream of lists will be called exactly when new data is needed.+--+-- Example:+--+-- >>> 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+-- Enter a list of Ints:+-- []+-- Enter a list of Ints:+-- []+-- Enter a list of Ints:+-- [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:+--+-- >>> let boolToList b = if b then ["Yes"] else []+-- >>> let everyOddEmpty = count >>> arr (even >>> boolToList)+-- >>> reactimate $ concatS everyOddEmpty >>> arrM print+-- "Yes"+-- "Yes"+-- "Yes"+-- "Yes"+-- "Yes"+-- ...+--+-- But this will be caught in a loop:+--+-- >>> let after3Empty = count >>> arr ((<= 3) >>> boolToList)+-- >>> reactimate $ concatS after3Empty  >>> arrM print+-- "Yes"+-- "Yes"+-- "Yes"+-- ^CInterrupted. concatS :: Monad m => MStream m [b] -> MStream m b concatS msf = MSF $ \_ -> tick msf []   where@@ -61,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,33 +1,44 @@+{-# LANGUAGE CPP        #-} {-# LANGUAGE Rank2Types #-}--- | Monadic Stream Functions are synchronized stream functions---   with side effects.+-- 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+-- Maintainer : ivan.perez@keera.co.uk -----   'MSF's are defined by a function---   @unMSF :: MSF m a b -> a -> m (b, MSF m a b)@---   that executes one step of a simulation, and produces an output in a---   monadic context, and a continuation to be used for future steps.+-- Monadic Stream Functions are synchronized stream functions with side+-- effects. -----   'MSF's are a generalisation of the implementation mechanism used by Yampa,---   Wormholes and other FRP and reactive implementations.+-- 'MSF's are defined by a function+-- @unMSF :: MSF m a b -> a -> m (b, MSF m a b)@+-- that executes one step of a simulation, and produces an output in a monadic+-- context, and a continuation to be used for future steps. -----   When combined with different monads, they produce interesting effects. For---   example, when combined with the 'Maybe' monad, they become transformations---   that may stop producing outputs (and continuations). The 'Either' monad---   gives rise to 'MSF's that end with a result (akin to Tasks in Yampa, and---   Monadic FRP).+-- 'MSF's are a generalisation of the implementation mechanism used by Yampa,+-- Wormholes and other FRP and reactive implementations. -----   Flattening, that is, going from some structure @MSF (t m) a b@ to @MSF m a b@---   for a specific transformer @t@ often gives rise to known FRP constructs.---   For instance, flattening with 'EitherT' gives rise to switching, and---   flattening with 'ListT' gives rise to parallelism with broadcasting.+-- When combined with different monads, they produce interesting effects. For+-- example, when combined with the 'Maybe' monad, they become transformations+-- that may stop producing outputs (and continuations). The 'Either' monad+-- gives rise to 'MSF's that end with a result (akin to Tasks in Yampa, and+-- Monadic FRP). -----   'MSF's can be used to implement many FRP variants, including Arrowized FRP,---   Classic FRP, and plain reactive programming. Arrowized and applicative---   syntax are both supported.+-- Flattening, that is, going from some structure @MSF (t m) a b@ to @MSF m a b@+-- for a specific transformer @t@ often gives rise to known FRP constructs.+-- For instance, flattening with 'EitherT' gives rise to switching, and+-- flattening with 'ListT' gives rise to parallelism with broadcasting. -----   For a very detailed introduction to 'MSF's, see:---   <http://dl.acm.org/citation.cfm?id=2976010>---   (mirror: <http://www.cs.nott.ac.uk/~psxip1/#FRPRefactored>).+-- 'MSF's can be used to implement many FRP variants, including Arrowized FRP,+-- Classic FRP, and plain reactive programming. Arrowized and applicative+-- syntax are both supported.+--+-- For a very detailed introduction to 'MSF's, see:+-- <http://dl.acm.org/citation.cfm?id=2976010>+-- (mirror: <http://www.cs.nott.ac.uk/~psxip1/#FRPRefactored>). module Data.MonadicStreamFunction.Core   ( -- * Types     MSF@@ -51,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, morphGS, feedback, reactimate, embed)+#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 @@ -107,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@@ -125,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@@ -138,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@@ -151,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:@@ -163,27 +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---- IPerez: There is an alternative signature for liftMStreamPurer that also--- works, and makes the code simpler:------ morphS :: Monad m => (m1 (b, MSF m1 a b) -> m (b, MSF m1 a b)) -> MSF m1 a b -> MSF m a b------ Then we can express:------ liftTransS = morphS lift--- liftBaseS  = morphS liftBase------ We could also define a strict version of morphS as follows:------ morphS'  f = morphS (f >=> whnfVal)---   where whnfVal p@(b,_) = b `seq` return p------ and leave morphS as a lazy version (by default).+    morph' m1F = morph . m1F
src/Data/MonadicStreamFunction/Instances/ArrowChoice.hs view
@@ -1,14 +1,21 @@-{-# LANGUAGE InstanceSigs         #-}+{-# LANGUAGE InstanceSigs #-} {-# OPTIONS_GHC -fno-warn-orphans #-}--- | Instance of 'ArrowChoice' for Monadic Stream Functions ('MSF').+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk -----   Import this module to include that (orphan) instance.+-- Instance of 'ArrowChoice' for Monadic Stream Functions ('MSF').+--+-- 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
@@ -1,24 +1,30 @@-{-# LANGUAGE InstanceSigs         #-}-{-# LANGUAGE RecursiveDo          #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE RecursiveDo  #-} {-# OPTIONS_GHC -fno-warn-orphans #-}--- | Instance of 'ArrowLoop' for Monadic Stream Functions ('MSF').+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk -----   Import this module to include that (orphan) instance.+-- Instance of 'ArrowLoop' for Monadic Stream Functions ('MSF'). -----   This is only defined for monads that are instances of 'MonadFix'.+-- Import this module to include that (orphan) instance.+--+-- This is only defined for monads that are instances of 'MonadFix'. module Data.MonadicStreamFunction.Instances.ArrowLoop where -import Data.MonadicStreamFunction.Core-import Data.MonadicStreamFunction.InternalCore+-- External imports+import Control.Arrow     (ArrowLoop (..))+import Control.Monad.Fix (MonadFix) --- External-import Control.Arrow-import Control.Monad.Fix+-- 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
@@ -1,30 +1,37 @@ {-# OPTIONS_GHC -fno-warn-orphans #-}--- | Instance of 'ArrowPlus' for Monadic Stream Functions ('MSF').+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk -----   Import this module to include that (orphan) instance.+-- Instance of 'ArrowPlus' for Monadic Stream Functions ('MSF'). -----   This is only defined for monads that are instances of 'MonadPlus'.+-- Import this module to include that (orphan) instance.+--+-- This is only defined for monads that are instances of 'MonadPlus'. module Data.MonadicStreamFunction.Instances.ArrowPlus where --- base-import Control.Arrow-import Control.Monad-import Control.Applicative+-- 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,10 +1,13 @@-{-# LANGUAGE TypeFamilies         #-} {-# OPTIONS_GHC -fno-warn-orphans #-}---- | Number instances for 'MSF's that produce numbers. This allows you to use---   numeric operators with 'MSF's that output numbers, for example,---   you can write:+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk --+-- Number instances for 'MSF's that produce numbers. This allows you to use+-- numeric operators with 'MSF's that output numbers, for example, you can+-- write:+-- -- @ -- msf1 :: MSF Input Double -- defined however you want -- msf2 :: MSF Input Double -- defined however you want@@ -18,13 +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,12 +1,17 @@+{-# LANGUAGE FlexibleContexts      #-} {-# LANGUAGE FlexibleInstances     #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TypeFamilies          #-} {-# LANGUAGE UndecidableInstances  #-}-{-# OPTIONS_GHC -fno-warn-orphans  #-}--- | '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:+{-# OPTIONS_GHC -fno-warn-orphans #-}+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- 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:+-- -- @ -- msf1 :: MSF Input (Double, Double) -- defined however you want -- msf2 :: MSF Input (Double, Double) -- defined however you want@@ -21,7 +26,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@@ -30,16 +35,27 @@ -- resolved. module Data.MonadicStreamFunction.Instances.VectorSpace where -import Control.Arrow-import Control.Arrow.Util-import Data.MonadicStreamFunction.Core-import Data.VectorSpace+-- External imports+import Control.Arrow    ((>>^))+import Data.VectorSpace (VectorSpace (..)) +-- 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-  zeroVector   = constantly zeroVector-  r   *^ msf   = msf >>^ (r *^)-  msf ^/ r     = msf >>^ (^/ r)-  (^+^)        = elementwise2 (^+^)-  (^-^)        = elementwise2 (^-^)-  negateVector = (>>^ negateVector)+instance (Monad m, Eq s, Num s, VectorSpace v s, Floating (MSF m a s))+      => VectorSpace (MSF m a v) (MSF m a s)+  where+    zeroVector   = constantly zeroVector+    (*^)         = elementwise2 (*^)+    (^/)         = elementwise2 (^/)+    (^+^)        = elementwise2 (^+^)+    (^-^)        = elementwise2 (^-^)+    negateVector = (>>^ negateVector)+    dot          = elementwise2 dot+    normalize v  = elementwise2 f v (norm v)+      where+        f v' nv'+          | nv' /= 0  = v' ^/ nv'+          | otherwise = error "normalize: zero vector"
src/Data/MonadicStreamFunction/InternalCore.hs view
@@ -1,52 +1,52 @@-{-# LANGUAGE ExplicitForAll #-}-{-# LANGUAGE Rank2Types     #-}--- | Monadic Stream Functions are synchronized stream functions---   with side effects.+{-# LANGUAGE Rank2Types #-}+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk -----   'MSF's are defined by a function---   @unMSF :: MSF m a b -> a -> m (b, MSF m a b)@---   that executes one step of a simulation, and produces an output in a---   monadic context, and a continuation to be used for future steps.+-- Monadic Stream Functions are synchronized stream functions with side+-- effects. -----   'MSF's are a generalisation of the implementation mechanism used by Yampa,---   Wormholes and other FRP and reactive implementations.+-- 'MSF's are defined by a function+-- @unMSF :: MSF m a b -> a -> m (b, MSF m a b)@+-- that executes one step of a simulation, and produces an output in a monadic+-- context, and a continuation to be used for future steps. -----   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.-+-- '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. By default, you should import+-- "Data.MonadicStreamFunction.Core" or "Data.MonadicStreamFunction" whenever+-- possible, and define your functions without accessing the MSF constructor.+-- 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.Arrow-import Control.Applicative-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 @@ -62,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@@ -77,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@@@ -110,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
@@ -1,18 +1,22 @@--- | Versions of arrow combinators that run things in parallel using 'par', if+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk+--+-- Versions of arrow combinators that run things in parallel using 'par', if -- 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
@@ -1,31 +1,31 @@--- | 'ReactHandle's.+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk ----- 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.-+-- '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. module Data.MonadicStreamFunction.ReactHandle where --- External-import Control.Monad.IO.Class-import Data.IORef---- Internal-import Data.MonadicStreamFunction-import Data.MonadicStreamFunction.InternalCore+-- External imports+import Control.Monad.IO.Class (MonadIO, liftIO)+import Data.IORef             (IORef, newIORef, readIORef, writeIORef) +-- 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,40 +1,40 @@-{-# LANGUAGE Arrows     #-}-{-# LANGUAGE Rank2Types #-}--- | Useful auxiliary functions and definitions.+{-# LANGUAGE Arrows #-}+{-# LANGUAGE CPP    #-}+-- |+-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016+-- License    : BSD3+-- Maintainer : ivan.perez@keera.co.uk+--+-- 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+-- 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 Data.MonadicStreamFunction.Core-import Data.MonadicStreamFunction.Instances.ArrowChoice ()-import Data.VectorSpace-import Prelude hiding (id, (.))+#if !MIN_VERSION_base(4,8,0)+import Data.Monoid (Monoid, mempty, mappend)+#endif -import Control.Monad.Trans.MSF.State+-- 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)@@ -55,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.@@ -78,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@@ -116,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 @@ -137,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.@@ -159,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